美文网首页
Android-LeakCanary检测内存泄漏

Android-LeakCanary检测内存泄漏

作者: 张正yi | 来源:发表于2018-01-13 10:42 被阅读0次

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

    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<CommUtils> 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<CommUtils>(new CommUtils(context));
            }  
          return WeakReferenceInstance.get();
        }
    }
    

    知识扩展

    1、什么是单例模式?

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

    2、什么是内存泄露

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

    相关文章

      网友评论

          本文标题:Android-LeakCanary检测内存泄漏

          本文链接:https://www.haomeiwen.com/subject/nmqcoxtx.html