Android內存泄漏檢測利器:LeakCanary

EdwardCople 7年前發布 | 5K 次閱讀 Android開發 移動開發 LeakCanary

Android內存泄漏檢測利器:LeakCanary

是什么?

一言以蔽之:LeakCanary是一個 傻瓜化 并且可視化的內存泄露分析工具

為什么需要LeakCanary?

因為它簡單,易于發現問題,人人可參與。

  • 簡單:只需設置一段代碼即可,打開應用運行一下就能夠發現內存泄露。而MAT分析需要Heap Dump,獲取文件,手動分析等多個步驟。
  • 易于發現問題:在手機端即可查看問題即引用關系,而MAT則需要你分析,找到Path To GC Roots等關系。
  • 人人可參與:開發人員,測試測試,產品經理基本上只要會用App就有可能發現問題。而傳統的MAT方式,只有部分開發者才有精力和能力實施。

如何集成

盡量在app下的build.gradle中加入以下依賴

在Application中加入類似如下的代碼

public class ExampleApplication extends Application {  
  @Override public void onCreate() {   
    super.onCreate();    
    LeakCanary.install(this); 
  }
}

到這里你就可以檢測到Activity的內容泄露了。其實現原理是設置Application的ActivityLifecycleCallbacks方法監控所有Activity的生命周期回調。內部實現代碼為

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();
    }
}

.... }</code></pre>

想要檢測更多?

首先我們需要獲得一個RefWatcher,用來后續監控可能發生泄漏的對象

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;  
  }
}

監控某個可能存在內存泄露的對象

MyApplication.getRefWatcher().watch(sLeaky);

哪些需要進行監控

默認情況下,是對Activity進行了檢測。另一個需要監控的重要對象就是Fragment實例。因為它和Activity實例一樣可能持有大量的視圖以及視圖需要的資源(比如Bitmap)即在Fragment onDestroy方法中加入如下實現

public class MainFragment extends Fragment {    
  @Override    
  public void onDestroy() {        
    super.onDestroy();        
    MyApplication.getRefWatcher().watch(this);    
  }
}

何時進行監控

首先,我們需要明確什么是內存泄露,簡而言之,某個對象在該釋放的時候由于被其他對象持有沒有被釋放,因而造成了內存泄露。

因此,我們監控也需要設置 在對象(很快)被釋放的時候 ,如Activity和Fragment的onDestroy方法。

一個錯誤示例,比如監控一個Activity,放在onCreate就會大錯特錯了,那么你每次都會收到Activity的泄露通知。

解決方案

常用的解決方法思路如下

  • 盡量使用Application的Context而不是Activity的
  • 使用弱引用或者軟引用
  • 手動設置null,解除引用關系
  • 將內部類設置為static,不隱式持有外部的實例
  • 注冊與反注冊成對出現,在對象合適的生命周期進行反注冊操作。
  • 如果沒有修改的權限,比如系統或者第三方SDK,可以使用反射進行解決持有關系

如何實現的

LeakCanary實際上就是在本機上自動做了Heap dump,然后對生成的hprof文件分析,進行結果展示。和手工進行MAT分析步驟基本一致。

實踐中的問題

  • 如果targetSdkVersion為23,在6.0的機器上會存在問題,卡死,因為LeakCanary并沒有很好支持 Marshmallow運行時權限 ,所以始終得不到sd卡權限,進而導致卡死。

注意

  • 目前LeakCanary一次只能報一個泄漏問題,如果存在內存泄漏但不是你的模塊,并不能說明這個模塊沒有問題。建議建議將非本模塊的泄漏解決之后,再進行檢測。

 

來自:http://www.jianshu.com/p/20484e01cf5b

 

 本文由用戶 EdwardCople 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!