你們好,我是蒼王。
html
如下是我這個系列的相關文章,有興趣能夠參考一下,能夠給個喜歡或者關注個人文章。android
[Android]如何作一個崩潰率少於千分之三噶應用app--章節列表git
LeakCanary,金絲雀,在組件化Gank研發的時候,近來踩了一下坑,發現其內存泄露檢測的思想很是精妙。github
能夠看到release debug所引用的leakcanary的工具是不一樣的。面試
工程目錄設計模式
其中leakcanary-android/leakcanary-android-no-op是依賴於leakcanary-analyzer。app
而leakcanary-analyzer依賴於leakcanary-watcher函數
工程使用的時候,須要在自定義的Application中使用工具
其還使用使用了StrictMode,這裏有StrictMode詳細介紹
源碼分析
RefWatcher對象的安裝
構建一個AndroidRefWatcherBuilder的對象
.
其是繼承於RefWatcherBuilder對象的
設置後臺的監聽
其設置的監聽者是用於分析泄露結果,和發送通知
在RefWatcherBuilder中設置excluedeRefs
這裏建立泄露路徑的記錄建造者
其最終會build方法建立一個ExcludedRefs的對象
其參數用於記錄泄露對象的路徑參數
使用buildAndAInstall構建出RefWatcher對象
能夠看出只支持4.0 ICS以上的
這裏在RefWatcherBuilder利用建造者設計模式設置參數
關於具體這些參數分析
1.watchExecutor 是線程控制器,控制activity銷燬後5s再去觀察泄露狀況
2.debuggerControl 控制debugger的,並未編寫任何執行事件
3.gcTrigger 用來觸發垃圾回收的,上面的線程控制器5s後觀察有泄露,不算泄露,必須垃圾回收後,再去觀察一次。因此最多會觀察兩次。第一次是5s後觀察,第二次是5s後在垃圾回收後觀察。
4.heapDumpListener hprof文件解釋完後,會告訴這個監聽者。這個監聽者就會更新狀態欄
5.excludedRefs 這玩意是作額外處理的,這裏面定義了一些類,若是是這些類泄露了,不會提示的。例如我就是想個人Activity泄露,你別管我,那你能夠把類名加到excludedRefs 中。
這裏面還要打開顯示泄露的Activity
這裏面DisplayLeakActivity就是顯示泄露的
咱們看到AndroidManifest裏面組件默認enabled =false的
並且這裏能夠看出HeapAnalyzerService分析內存泄露的後臺是新的進程
這裏使用PackageManager的setComponedtEnabledSettings開啓。
正是這樣,才能一開始未存在泄露時隱藏leakCanary的圖標。
經過ActivityRefWatcher.install啓動監聽泄露
經過監聽application.registerActivityLifecyleCallbacks的方法來監聽週期
經過查看監聽ActivityLifecycleCallbacks的回調監聽destroy的方法。
啓動對前臺的Activity的檢測
轉化爲對象去觀看
能夠看到此時建立一個持有Activity的弱引用
經過watchExcuter執行調用
這裏面會是用的是AndroidWatchExcuter的對象
其時間是5秒
咱們這裏能夠看到其會去持有主消息隊列和建立出線程的消息隊列
而後調用execute的方法來,不管waitForIdle或是postWaitForIdle,都是須要切換到主隊列。
而後使用MessageQueue.IdleHandler能夠用來在線程空閒的時候,指定一個操做,使用IdleHandler的好處在於能夠不用指定一個未來時間,只要線程空閒了,就能夠執行它指定的操做。
這裏是使用Retryable,是有枚舉狀態的,若是是RETRY的返回狀態,會從新執行。
AndroidWatchExcuter會調用ensureGone的方法
這裏會須要試着移除弱引用,
判斷隊列裏面是是否有對應Activity的弱引用對象
而後試着在retainedKeys集合裏面試着移除
再次判斷是否在集合中是否還包含引用對象,若是不包含就說明沒有泄露
這裏繼續會走GC內存回收的流程
RunTime.getRunTime().gc()觸發系統gc操做
enqueueReference經過強制限制100毫秒的時間給gc
System.runFinalization()是強制調用已經失去引用的對象的finalize方法
而後再進行弱引用對象移除
在判斷若是依然沒被移除,會調用heapDumper.dumpHeap的方法
這裏泄露目錄的定義
默認最多七個Dump文件
這裏調用dumpHeap會建立文件.hrof的文件
newHeapDumpFile來建立.hrof文件
這裏使用Debug.dumpHprofData這個類,是heap堆的快照,能夠獲知程序的哪些部分正在使用大部分的內存
而後使用heapdumpListener.analyze的方法分析堆內存
這裏heapdumpListener使用的是AndroidRefWatcherBuilder裏面的
進一步看到是使用HeapAnalyzerService.runAnalysis的方法
這裏是啓動一個其自身做爲一個IntentService,
啓動IntentService就會直接運行onHanldeIntent的方法,運行完就會釋放回收掉Service
這裏HeapAnalyzer會使用checkForLeak的方法來分析內存泄露結果
而後回調結果給上層的DisplayLeakService來處理結果
會調用findLeakTrace的偵測
這裏創建檢測泄露節點和返回泄露對象的詳細信息。
這裏最終會調用到squaredup的haha庫,專用於分析Android的堆分析
咱們看看將結果回調給Service的時候,會啓動Service,而後將相應的result參數傳遞過去
咱們看到IntentService,會調用onHeapAnalyzed的方法
DisplayLeakService被啓動後讀取相應的參數
能夠看到設置了一些顯示的參數後,會提示Notification和處理堆
LeackCanaryInternals發送Notification到狀態欄
其通知的pendingIntent實際跳轉到DisplayLeakActivity
這裏提供了最終調用的方法給用戶本身處理。
關於DisplayLeakActivity就是要將AnalysisResult展現出來。
其使用LIstView顯示路徑的時候,TextView的解析是使用html.forHtml來解析HTML文本拼接
咱們能夠看到其使用elementToHtmlString來拼接Html文本
具體Html文本的用法能夠參考Android TextView使用HTML處理字體樣式、顯示圖片等
而後回到一開始的Application裝載LeakCanary,
其使用isInAnalyzerProcess分析應用函數
判斷是否在後臺進程
而後這裏LeakCanary封裝了一個很是好的判斷是否後臺進程的方法。
顯然leakCanary的設計很是精妙,能夠很是容易檢測的大部份內存泄漏了。
可是暫時發現的缺陷
1.若是首頁的Activity一直不銷燬(onDestroy)那麼將一直沒法檢測到首頁的調用棧的內存泄漏
2.沒法檢測Service產生的內存泄漏。
這節就到這裏,
下一節將會更精彩,敬請期待!!!
羣號是316556016,也能夠掃碼進羣。我在這裏期待大家的加入!!!