Android性能优化之LeakCanary内存泄漏检测原理分析

LeakCanary内存泄漏检测原理分析

一、LeakCanary原理介绍

LeakCanary如何检测内存泄漏的呢?主要分为7步:

  • 1、RefWatcher.watch()创建了一个KeyedWeakReference用于去观察对象。

  • 2、然后,在后台线程中,它会检测引用是否被清除了,并且是否没有触发GC。

  • 3、如果引用仍然没有被清除,那么它将会把堆栈信息保存在文件系统中的.hprof文件里。

  • 4、HeapAnalyzerService被开启在一个独立的进程中,并且HeapAnalyzer使用了HAHA开源库解析了指定时刻的堆栈快照文件heap dump。

  • 5、从heap dump中,HeapAnalyzer根据一个独特的引用key找到了KeyedWeakReference,并且定位了泄露的引用。

  • 6、HeapAnalyzer为了确定是否有泄露,计算了到GC Roots的最短强引用路径,然后建立了导致泄露的链式引用。

  • 7、这个结果被传回到app进程中的DisplayLeakService,然后一个泄露通知便展现出来了。

官方原理解释是:

在一个Activity执行完onDestroy后,将它放入到WeakReference中,然后将这个WeakReference类型的Activity的对象与ReferenceQueue关联,注意: 如果一个对象要被GC回收了,会把它引用的对象放入到ReferenceQueue中。这时候只需要在ReferenceQueue中去查找是否存在该对象,如果没有就执行一个GC,再次查找,如果还是没有,则说明该对象可能无法被回收,也就可能发生了内存泄漏,最后使用HAHA这个开源库取分析dump之后的heap内存。

二、为什么要使用LeakCanary

我们知道内存泄漏问题的排查有很多种方法, 比如说,Android Studio 自带的 Profile 工具、MAT(Memory Analyzer Tool)、以及LeakCanary。 选择 LeakCanary 作为首选的内存泄漏检测工具主要是因为它能实时检测泄漏并以非常直观的调用链方式展示内存泄漏的原因

三、LeakCanary的使用

1、在app中的build.gradle中配置:

dependencies {
  debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.2'
  releaseImplementation   'com.squareup.leakcanary:leakcanary-android-no-op:1.6.2'
  // 可选,如果你使用支持库的fragments的话
  debugImplementation   'com.squareup.leakcanary:leakcanary-support-fragment:1.6.2'
}

2、然后在Application中配置:

public class WanAndroidApp extends Application {

    private RefWatcher refWatcher;

    public static RefWatcher getRefWatcher(Context context) {
        WanAndroidApp application = (WanAndroidApp)     context.getApplicationContext();
        return application.refWatcher;
    }

    @Override public void onCreate() {
      super.onCreate();
      if (LeakCanary.isInAnalyzerProcess(this)) {
        // 1
        return;
      }
      // 2
      refWatcher = LeakCanary.install(this);
    }
}

在注释1处,会首先判断当前进程是否是Leakcanary专门用于分析heap内存的而创建的那个进程,即HeapAnalyzerService所在的进程,如果是的话,则不进行Application中的初始化功能。如果是当前应用所处的主进程的话,则会执行

注释2处的LeakCanary.install(this)进行LeakCanary的安装。只需这样简单的几行代码,我们就可以在应用中检测是否产生了内存泄露了。当然,这样使用只会检测Activity是否发生内存泄漏,如果要检测Fragment在执行完onDestroy()之后是否发生内存泄露的话,则需要在FragmentonDestroy()方法中加上如下两行代码去监视当前的Fragment:

RefWatcher refWatcher = WanAndroidApp.getRefWatcher(_mActivity);
refWatcher.watch(this);

上面的RefWatcher其实就是一个引用观察者对象,是用于监测当前实例对象的引用状态的。从以上的分析可以了解到,核心代码就是LeakCanary.install(this)这行代码,接下来,就从这里出发将LeakCanary一步一步进行拆解。

四、LeakCanary源码分析

待定。。。

五、LeakCanary执行的流程

六、总结

LeakCanary 的原理总结如下

  • 监听 Activity 的生命周期

  • 在 onDestroy 的时候,创建相应的 Refrence 和 RefrenceQueue,并启动后台进程去检测

  • 一段时间之后,从 RefrenceQueue 读取,若读取不到相应 activity 的 Refrence,有可能发生泄露了,这个时候,再触发 gc,一段时间之后,再去读取,若在从 RefrenceQueue 还是读取不到相应 activity 的 refrence,可以断定是发生内存泄露了

  • 发生内存泄露之后,dump,分析 hprof 文件,找到泄露路径(使用 haha 库分析)

其中,比较重要的是如何确定是否发生内存泄露,而如何确定发生内存泄露最主要的原理是通过 Refrence 和 RefrenceQueue


   转载规则


《Android性能优化之LeakCanary内存泄漏检测原理分析》 mikyou 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
Android性能优化之Bitmap优化 Android性能优化之Bitmap优化
Android性能优化之Bitmap优化一、Bitmap内存模型 1、Android 2.2(API8)之前,当GC工作时,应用的线程会暂停工作,同步的GC会影响性能。 2、Android2.3之后,GC变成了并发的,意味着Bitmap
2020-01-01
下一篇 
Android性能优化之内存优化 Android性能优化之内存优化
Android性能优化之内存优化一、内存泄漏(Memory Leak) 对于Java来说new出来的Object在Heap堆上无法被GC回收(内存中存在无法回收的对象);内存泄漏时主要表现为内存抖动,可用内存慢慢变少。 1、内存泄漏检测工
2020-01-01