Android-LeakCanary检测内存泄漏

此文章仅用于个人学习笔记,如有雷同还望见谅

LeakCanary地址:leakcanary

一、使用:

第一步:在build.gradle配置如下:

dependencies { 
  debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.4'
  releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'
}

第二步:在Application中添加:

 if (LeakCanary.isInAnalyzerProcess(this)) {
           // This process is dedicated to LeakCanary for heap analysis.
           // You should not init your app in this process.
           return;
  }
  LeakCanary.install(this);
  // Normal app init code...

上面的配置只是对你的activity的内容中存在的泄露进行了监控,如果有泄露发生,LeakCanary就会弹出一个提示框。当然你也可以对其他对象进行监控,需要用到RefWatcher这个类去主动监控某个对象,比如Fragment。

LeakCanary在调用install方法时会启动一个ActivityRefWatcher类,它用于自动监控Activity执行onDestroy方法之后是否发生内存泄露。如果想要监控Fragment,在Fragment中添加如下的onDestroy方法。

修改如下:

public class MyApplication extends Application {
    private RefWatcher refWatcher;
    @Override
    public void onCreate() {
        super.onCreate();
        refWatcher = setupLeakCanary();
    }

    private RefWatcher setupLeakCanary() {
        if (LeakCanary.isInAnalyzerProcess(this)) {
            return RefWatcher.DISABLED;
        }
        return LeakCanary.install(this);
    }
    /**
     * 静态方法来返回全局RefWatcher
     *
     * @param context
     * @return
     */
    public static RefWatcher getRefWatcher(Context context) {
        MyApplication leakApplication = (MyApplication) context.getApplicationContext();
        return leakApplication.refWatcher;
    }
}

Fragment对应代码如下:

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

最后,安装应用,在debug版本的apk安装后,会出现如下两个图标:左边的是自己应用的图标,右边是启动应用后退出,自动安装的leakCancayDe图标。

二、分析

1、单例所引起的内存泄露

如下一段单例代码:

    private static CommUtils instance;
    private Context context;
    public CommUtils(Context context) { 
         this.context = context;  
     }  
    public static CommUtils getInstance(Context context){ 
       if (instance == null){ 
           instance = new CommUtils(context);
        }  
      return instance;
    }
/**该类在MainActivity中的使用如下代码:**/
// CommUtils commUtils = CommUtils.getInstance(this);

上面的这段代码是我们在写单例的时候经常写的,但是在这个单例的使用是存在内存泄露风险的;

原因是:当手机进行横竖屏切换的时候或者Activity过多内存使用紧张的时候,系统销毁Activity,但在这个时候该Activity被CommUtils工具类所持有,导致Activity无法被系统回收从而导致内存泄露

1.1如何解决 (保证Context和AppLication的生命周期一样)

有两种方式解决该单例所导致的内存泄露:

  • 第一种方式是使用全局的Application上下文Context参数使用CommUtils,如下:
      this.context = context.getApplicationContext();
       // or CommUtils commUtils = CommUtils.getInstance(getApplicationContext());
    
  • 第二种方式使用弱引用的方式解决代码如下:
    private static WeakReference WeakReferenceInstance;
    private Context context;
    public CommUtils(Context context) { 
         this.context = context;  
     }  
    public static CommUtils getInstance(Context context){ 
       if (WeakReferenceInstance == null || WeakReferenceInstance.get() == null) {
           WeakReferenceInstance = new WeakReference(new CommUtils(context));
        }  
      return WeakReferenceInstance.get();
    }
}

知识扩展

1、什么是单例模式?

 使用时,单例的对象必须保证只有一个实例存在,不予许自由构造对象
 确保某个类有且只有一个实例,而且自行实例化并向整个系统提供这个实例

2、什么是内存泄露

当一个对象已经不被使用,本应当别回收,但被另一个正在使用的对象所吃用,导致该对象无法被回收;

你可能感兴趣的:(Android-LeakCanary检测内存泄漏)