Android內存泄漏檢測利器:LeakCanary
是什么?
一言以蔽之:LeakCanary是一個傻瓜化并且可視化的內存泄露分析工具
為什么需要LeakCanary慨代?
因為它簡單,易于發(fā)現(xiàn)問題扒腕,人人可參與寞钥。
- 簡單:只需設置一段代碼即可,打開應用運行一下就能夠發(fā)現(xiàn)內存泄露雷激。而MAT分析需要Heap Dump,獲取文件告私,手動分析等多個步驟侥锦。
- 易于發(fā)現(xiàn)問題:在手機端即可查看問題即引用關系,而MAT則需要你分析德挣,找到Path To GC Roots等關系恭垦。
- 人人可參與:開發(fā)人員,測試測試,產品經理基本上只要會用App就有可能發(fā)現(xiàn)問題番挺。而傳統(tǒng)的MAT方式唠帝,只有部分開發(fā)者才有精力和能力實施。
如何集成
盡量在app下的build.gradle中加入以下依賴
在Application中加入類似如下的代碼
public class ExampleApplication extends Application {
@Override public void onCreate() {
super.onCreate();
LeakCanary.install(this);
}
}
到這里你就可以檢測到Activity的內容泄露了玄柏。其實現(xiàn)原理是設置Application的ActivityLifecycleCallbacks方法監(jiān)控所有Activity的生命周期回調襟衰。內部實現(xiàn)代碼為
public final class ActivityRefWatcher {
private final ActivityLifecycleCallbacks lifecycleCallbacks = new ActivityLifecycleCallbacks() {
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
public void onActivityStarted(Activity activity) {
}
public void onActivityResumed(Activity activity) {
}
public void onActivityPaused(Activity activity) {
}
public void onActivityStopped(Activity activity) {
}
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
public void onActivityDestroyed(Activity activity) {
ActivityRefWatcher.this.onActivityDestroyed(activity);
}
};
private final Application application;
private final RefWatcher refWatcher;
public static void installOnIcsPlus(Application application, RefWatcher refWatcher) {
if(VERSION.SDK_INT >= 14) {
ActivityRefWatcher activityRefWatcher = new ActivityRefWatcher(application, refWatcher);
activityRefWatcher.watchActivities();
}
}
....
}
想要檢測更多?
首先我們需要獲得一個RefWatcher,用來后續(xù)監(jiān)控可能發(fā)生泄漏的對象
public class MyApplication extends Application {
private static RefWatcher sRefWatcher;
@Override public void onCreate() {
super.onCreate();
sRefWatcher = LeakCanary.install(this);
}
public static RefWatcher getRefWatcher() {
return sRefWatcher;
}
}
監(jiān)控某個可能存在內存泄露的對象
MyApplication.getRefWatcher().watch(sLeaky);
哪些需要進行監(jiān)控
默認情況下粪摘,是對Activity進行了檢測瀑晒。另一個需要監(jiān)控的重要對象就是Fragment實例。因為它和Activity實例一樣可能持有大量的視圖以及視圖需要的資源(比如Bitmap)即在Fragment onDestroy方法中加入如下實現(xiàn)
public class MainFragment extends Fragment {
@Override
public void onDestroy() {
super.onDestroy();
MyApplication.getRefWatcher().watch(this);
}
}
何時進行監(jiān)控
首先徘意,我們需要明確什么是內存泄露苔悦,簡而言之,某個對象在該釋放的時候由于被其他對象持有沒有被釋放椎咧,因而造成了內存泄露玖详。
因此,我們監(jiān)控也需要設置在對象(很快)被釋放的時候勤讽,如Activity和Fragment的onDestroy方法蟋座。
一個錯誤示例,比如監(jiān)控一個Activity脚牍,放在onCreate就會大錯特錯了向臀,那么你每次都會收到Activity的泄露通知。
解決方案
常用的解決方法思路如下
- 盡量使用Application的Context而不是Activity的
- 使用弱引用或者軟引用
- 手動設置null诸狭,解除引用關系
- 將內部類設置為static飒硅,不隱式持有外部的實例
- 注冊與反注冊成對出現(xiàn),在對象合適的生命周期進行反注冊操作作谚。
- 如果沒有修改的權限,比如系統(tǒng)或者第三方SDK庵芭,可以使用反射進行解決持有關系
如何實現(xiàn)的
LeakCanary實際上就是在本機上自動做了Heap dump妹懒,然后對生成的hprof文件分析,進行結果展示双吆。和手工進行MAT分析步驟基本一致眨唬。
實踐中的問題
- 如果targetSdkVersion為23,在6.0的機器上會存在問題好乐,卡死匾竿,因為LeakCanary并沒有很好支持Marshmallow運行時權限,所以始終得不到sd卡權限蔚万,進而導致卡死岭妖。
注意
- 目前LeakCanary一次只能報一個泄漏問題,如果存在內存泄漏但不是你的模塊,并不能說明這個模塊沒有問題昵慌。建議建議將非本模塊的泄漏解決之后假夺,再進行檢測。