LeakCanary原理

1.LeakCanary介绍

相信很多做Android开发的小哥都用过LeakCanary,LeakCanary是Square公司开源的内存泄露检测工具,对我们日常开发有较大的帮助。看了jvm内存回收的小伙伴应该知道内存泄漏的原因,而LeakCanary又是怎么检测的呢?今天我主要从源码上来看看他的实现方式。

2.源码分析

LeakCanary源码分析我们从install方法开始,大家应该知道引入LeakCanary的时候install方法时在Application#onCreate的方法中执行的。

我们首先看isInAnalyzerProcess方法,看注释如果是LeakCanary进程就不允许初始化其他任务。这个进程是为LeakCanary分析堆内存用的。

截屏2021-06-02 00.17.38.png

截屏2021-06-02 00.18.06.png
我们知道引入LeakCanary在你的项目编译成功之后会自动安装一个Leaks apk。看到上面LeakCanary.install(this)这行代码,是不是安装Leaks apk?是不是Leaks通过跨进程来检测我项目呢?检测原理又是怎样的?带着这些问题,接下来看看具体做了什么事情。会调用LeakCanary#install方法

截屏2021-06-02 00.18.23.png
首先我们看看buildAndInstall方法具体做了什么事情

截屏2021-06-02 00.18.48.png
看ActivityRefWatcher类名应该是Activity 引用监控,我们跟进这个installOnIcsPlus方法看看

截屏2021-06-02 00.19.12.png
然后installOnIcsPlus方法又调用了ActivityRefWatcher#watchActivities方法,我们再跟进分析

截屏2021-06-02 00.19.49.png
我们首先看看Application#registerActivityLifecycleCallbacks方法,我们知道原理registerActivityLifecycleCallbacks是注册Activity生命周期回调的方法。管理生命周期的方法,每个Activity都会回调到这里。我们看lifecycleCallbacks这个变量对应着Activity的生命周期。
到这里所以我们是不是可以猜想到LeakCanary其实就是通过注册Activity生命周期回调来监控检查是否有内存泄露的。当Activity界面关闭回调用对应的onActivityDestroyed方法。
接下来我们看看Application.ActivityLifecycleCallbacks#onActivityDestroyed方法干了些什么事情。

截屏2021-06-02 00.20.08.png

截屏2021-06-02 00.20.12.png
接下来会调用到com.squareup.leakcanary.RefWatcher#watch(java.lang.Object)方法。

截屏2021-06-02 00.21.01.png
将其Activity引用包装成一个KeyedWeakReference弱引用。被WeakReference包装的引用如果被回收会添加到ReferenceQueue队列中,WeakReference和ReferenceQueue将在接下来的文章里分析。WeakReference和ReferenceQueue
通过检查ReferenceQueue里的Activity引用来检测是否能够被回收。下面具体看看检测方法:

截屏2021-06-02 00.21.22.png
通过ensureGone这个方法名可以看出应该是确保引用释放的意思。具体看看ensureGone方法做了些什么:

我们主要看removeWeaklyReachableReferences(),gcTrigger.runGc(),heapdumpListener.analyze()这三个方法。

1.通过removeWeaklyReachableReferences移除所有ReferenceQueue队列的WeakReference对象的Activity引用。如果可以回收就直接返回。

截屏2021-06-02 00.21.53.png
2.Activity引用如果通过removeWeaklyReachableReferences还是没有移除就通过gcTrigger.runGc()来GC触发回收。

3.接下来再触发步骤1的removeWeaklyReachableReferences方法来移除Activity引用,判断是否回收,如果可以回收就直接返回,反之就说明对象泄露了就会触发heapdumpListener.analyze()方法来分析,看到HeapDump对象,我们可以通过heapDumper.dumpHeap()方法看到dump当前的heap hprof快照文件。
具体通过Debug.dumpHprofData(heapDumpFile.getAbsolutePath())方法去dump内存文件的。实现如下:

截屏2021-06-02 00.22.17.png
接下来会调用com.squareup.leakcanary.ServiceHeapDumpListener#analyze方法将内存文件目录等相关信息通过HeapAnalyzerService#runAnalysis方法来进行对象内存泄露的分析。实现如下:

截屏2021-06-02 00.22.36.png
接着会启动HeapAnalyzerService IntentService服务。

截屏2021-06-02 00.23.08.png
具体在HeapAnalyzerService#onHandleIntent方法中通过HeapAnalyzer#checkForLeak来检测是否内存泄露的。实现如下:

截屏2021-06-02 00.23.44.png
接下来启动AbstractAnalysisResultService这个IntentService,启动后会调用onHandleIntent方法。

截屏2021-06-02 00.24.05.png
最终通过onHeapAnalyzed这个抽象方法将heapDump,AnalysisResult信息传入到子类实现。

截屏2021-06-02 00.24.36.png

截屏2021-06-02 00.24.44.png
分析上面逻辑其实就是通过DisplayLeakService做内存泄露相关展示。

3.总结

LeakCanary利用Application#registerActivityLifecycleCallbacks Activity生命周期回调onActivityDestroyed方法通过调用RefWatcher#wather方法来检测对象是否回收,通过removeWeaklyReachableReferences—>gcTrigger.runGc—>removeWeaklyReachableReferences—>heapdumpListener.analyze 三步二次检测来确定内存泄露,最终dump 内存信息来分析到最终显示分析出的泄露信息。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享