? ? ? 說到內存泄漏脸哀,就必須提到LeakCanary. 這個利器图筹,很方便的顯示出內存泄漏的地方篇裁。在用到的過程中好奇怎么做到的,下面跟著網(wǎng)上的博客簡單的分析下LeakCanary源碼吵护。
? ?源碼分析
1. 注冊
使用很簡單盒音,關鍵的一行代碼“LeakCanary.install(this)”;下面就以這行代碼為線索分析。
構建一個AndroidRefWatcherBuilder的對象馅而。
而AndroidRefWatcherBuilder繼承自RefWatcherBuilder祥诽。
創(chuàng)建的實際是子類對象,因此后續(xù)調用的都是子類的方法瓮恭,除非子類不存在雄坪,則會調用父類的方法。
而傳進去的參數(shù)DisplayService.這個類是用于內存泄漏后的展示偎血。
這個是創(chuàng)建那些需要去除的引用诸衔,因為有些內存泄漏是已知,且是系統(tǒng)層級的颇玷。因此判斷是否內存泄漏的時候需要排除笨农。這個也可以手動增加,比如這個類的泄漏不嚴重帖渠,但改起來代價太大谒亦,就可以手動將這個類放進去。
最后調用這個方法空郊,關鍵的地方在于build()這個方法份招,通過建造者設計模式設置參數(shù)。因為前面創(chuàng)建的是子類對象狞甚,因此調用方法時會優(yōu)先調用子類的方法锁摔。另外值得注意的是最后new RefWatcher時,會去創(chuàng)建一個Disabled的父類的對象哼审,也會去調用build()方法谐腰。
enableDisplayLeakActivity 這個用來控制內存泄漏圖標的顯示與否孕豹。
注冊activity的ActivityLifecycleCallbacks. 這樣就可以在activity的ondestroy方法中執(zhí)行內存泄漏的檢查。其實可以從此處看出LeakCanary 的缺點十气,一個是只能檢測到activity的內存泄漏励背,另一個是只能檢測非前臺的activity的內存泄漏。比如service 的內存泄漏就檢測不到砸西。
2 檢測
當activity 執(zhí)行到ondestroy 方法時叶眉,會回調ActivityLifecycleCallbacks.
然后開始進行內存泄漏的檢查,一路跟進去關鍵代碼如下:
而這個watchExcuter 則是在最開始install 的時候通過builder 方法創(chuàng)建芹枷。實際如下
關鍵代碼如下
Retryable 實際上是一個runnable對象衅疙。可以看到execute的retryable,最后都會在主進程中執(zhí)行杖狼。
而MessageQueue.IdleHandler可以用來在線程空閑的時候炼蛤,指定一個操作妖爷,使用IdleHandler的好處在于可以不用指定一個將來時間蝶涩,只要線程空閑了,就可以執(zhí)行它指定的操作絮识。
這個是界面跳轉后內存泄漏的檢查需要稍等下的原因之一绿聘。另外一個原因可能是生成分析dump文件比較費時。
接下來回頭看ensuregone方法
removeWeaklyReachableReferences方法會需要試著移除弱引用次舌,如果移除后的集合中不包括activity的引用對象熄攘。則說明沒有泄漏,否則就需要手動gc, 然后通過removeWeaklyReachableReferences檢查gc后 彼念。如果此時集合中還有activity對應的引用對象挪圾,就說明內存泄漏了。否則就不認為發(fā)生內存泄漏逐沙。如果發(fā)生內存泄漏哲思,接下來就需要檢測出到底什么地方發(fā)生了泄漏。
此時的heapDumper也是最開始install的時候通過build()方法構造的吩案。
這個地方是調用的系統(tǒng)的Debug類的dumpHprofData棚赔,來生成dump文件,文件名就是傳進去的參數(shù)徘郭。值得深挖的是Debug這個類靠益,有很多有用的幫助調試的方法。
生成文件之后 然后會走到heapDumpListener残揉。通過analyze 開始正式對dump文件分析胧后。
然后就調到HeapAnalyzerService的runAnalysis方法。HeapAnalyzerService是一個intentservice類抱环,執(zhí)行結束壳快,這個service會自動銷毀途样。然后runAnalysis調用到onHandleIntent 方法中去。需要注意的是濒憋,因為HeapAnalyzerService在manifest中是標記的另外的進程何暇,所以此處雖然是startservice,這樣啟動service,但啟動的service 運行在新的進程中凛驮。
HeapAnalyzer會使用checkForLeak的方法來分析內存泄露結果裆站。
這里又個值得注意的地方是,老版本的LeakCanary使用的是eclipse.mat 這個包來分析的黔夭。而新版本的則是使用的squaredup的haha庫宏胯。
此處也是跨進程調用的。然后結果就會傳給最開始的displayleakservice本姥。然后就會發(fā)通知到通知欄肩袍。然后開發(fā)者就可以很方便的點進去看到相關的內存泄漏了。
3 總結
一路下來婚惫,代碼并不是很難氛赐,不過多看幾遍就會有收獲的。有如下知識點:
ActivityLifecyleCallbacks的使用
弱引用及referenceQueu的使用
builder 構造者設計模式
簡單的startservice 跨進程通信
MessageQueue.IdleHandler可以用來在線程空閑的時候先舷,指定一個操作
Debug輔助調試類艰管。
引用
http://www.reibang.com/p/481775d198f0
這篇文章講的很好,基本上就是自己想說的蒋川,截圖什么的都是來自這篇文章牲芋。感謝分享。