標籤:分析檔案 工具 其他 xtend java 工作 strong 地址 二次
一、什麼是LeakCanary?
LeakCanary就是用來檢測Android端記憶體流失的一個工具。能夠檢測Activity的泄漏
什麼是記憶體流失?
Java 對象有時也會”長死不死“,GC 拿它沒有辦法,這種情況就是記憶體流失。造成這種情況的原因是:Java 對象被另一個生命週期更長對象持有,具有 可達性 ,這並不是我們想要的。
來自 <http://www.jianshu.com/p/3f1a1cc1e964>
記憶體流失的危害?
記憶體流失最終將導致記憶體溢出,也就是OOM,並且OOM發生在某一處,並不代表問題就是出在那裡的,只是剛好有一塊記憶體申請,此時記憶體又不夠了才導致的,比較容易出現在申請比較大的記憶體的情況下。但是把這塊申請的記憶體降低並不能從根本上解決問題。
這裡有一個問題就是:記憶體的分配方式,分配位置,比如BitMap的分配,以及其他對象的分配?以及Activity對對象的持有,這個概念還不是很清晰。
github上的地址:https://github.com/square/leakcanary
一個原理的介紹內容在這裡:
https://www.liaohuqiu.net/cn/posts/leak-canary/
https://www.liaohuqiu.net/cn/posts/leak-canary-read-me/
二、LeakCanary的工作原理是什嗎?
這三個都有講解,並且還有直接通過源碼來進行講解的,後面可以針對這塊,針對源碼專門研究一下。
http://www.jianshu.com/p/a8900eb3de12
http://www.jianshu.com/p/5ee6b471970e
http://www.jianshu.com/p/3f1a1cc1e964
工作原理是:
LeakCanary會開啟一個Service,這個Service能夠在一個Activity被OnDestory之後,檢測是否真的還有這個對象,如果還有,會嘗試進行二次確認,如果這個對象還是沒有被釋放掉,則會擷取當時的記憶體狀態,產生一個heap的狀態檔案,然後分析檔案,計算這個對象的GC ROOT的最短強引用路徑,確定是否泄漏,如果有泄漏,Leak的APP就會有一條通知欄訊息出現
檢測流程圖如下:
三、如何使用
1、在build.gradle中引入:
debugCompile ‘com.squareup.leakcanary:leakcanary-android:1.3.1‘ // or 1.4-beta1
releaseCompile ‘com.squareup.leakcanary:leakcanary-android-no-op:1.3.1‘ // or 1.4-beta1
testCompile ‘com.squareup.leakcanary:leakcanary-android-no-op:1.3.1‘ // or 1.4-beta1
或者,現在最新的1.5.1的也可以直接用:
dependencies{
compile‘com.squareup.leakcanary:leakcanary-android:1.5.1‘
}
2、同時,在Application的方法,在OnCreate中添加install
public class DemoApplication extends Application {
@Override public void onCreate() {
super.onCreate();
LeakCanary.install(this);
}
}
3、在添加之後,直接打出來應用的包,裝上之後,會看到有一個附屬應用出來,名字叫做Leaks
4、直接操作APP,如果發現有記憶體流失,則這個過程中會有通知欄提示,點擊查看即可,可以將泄漏的資訊分享,也可以將當時的heap dump的資訊分享出來(但有可能這個heap dump不一定存在)
以檢測出來的一個圖為例:
LeakCanary的記憶體泄露提示一般會包含三個部分:
第一部分(LeakSingle類的sInstance變數)引用第二部分(LeakSingle類的mContext變數), 導致第三部分(MainActivity類的執行個體instance)泄露.
下方是一些更詳細的原理的講解:
1、不同的幾種引用方式:強-軟-弱-虛
2、LeakCanary這裡,有一個原理的講解叫做:
需要理解為什麼要用WeakReference,因為GC的時候是不會對強引用的做處理,而軟引用的是在記憶體不夠用了才會被回收,而弱引用就是可以隨時回收,所以需要用WeakReference對待檢測的對象進行包裹引用,因為是弱引用的,因此在待檢測對象調用了Destory或者Finish方法之後,被WeakReference引用的對象的生命週期結束,因為這個是弱引用,就會被GC檢測到,這個時候GC會把該對象添加到ReferenceQueue中,如果GC結束該對象還是沒有被加入到ReferenceQueue中,則說明可能存在記憶體流失,其實就是找到所有生命週期結束的對象,過濾掉會被回收的,剩下就是沒有被回收的,然後會做二次GC,之後還是沒有回收,就可以找到當時的記憶體狀態,拿到不同對象的引用情況,得到一個hprof的檔案,之後就能找到最短強引用的路徑。
解決記憶體流失,通過以下方式:
然後我們需要解決:如何得到未被回收的對象。ReferenceQueue+WeakReference+手動調用 GC可實現這個需求。
- WeakReference 建立時,傳入一個 ReferenceQueue 對象。當被 WeakReference 引用的對象的生命週期結束,一旦被 GC 檢查到,GC 將會把該對象添加到 ReferenceQueue 中,待ReferenceQueue處理。當 GC 過後對象一直不被加入 ReferenceQueue,它可能存在記憶體流失。
獲得未被回收的 Object
- 找到了未被回收的對象,如何確認是否真的記憶體流失?這裡可以將問題轉換為:未被回收的對象,是否被其他對象引用?找出其最短引用鏈。VMDebug + HAHA 完成需求。
VM 會有堆內各個對象的引用情況,並能以hprof檔案匯出。HAHA 是一個由 square 開源的 Android 堆分析庫,分析 hprof 檔案產生Snapshot對象。Snapshot用以查詢對象的最短引用鏈。
解析hprof
- 找到最短引用鏈後,定位問題,排查代碼將會事半功倍。
如下泳道圖分析, LeakCanary 各個模組如何配合達到檢測目的。
來自 <http://www.jianshu.com/p/3f1a1cc1e964>
【Android記憶體流失檢測】LeakCanary使用總結