1.LeakCanary介绍
相信很多做Android开发的小哥都用过LeakCanary,LeakCanary是Square公司开源的内存泄露检测工具,对我们日常开发有较大的帮助。看了jvm内存回收的小伙伴应该知道内存泄漏的原因,而LeakCanary又是怎么检测的呢?今天我主要从源码上来看看他的实现方式。
2.源码分析
LeakCanary源码分析我们从install方法开始,大家应该知道引入LeakCanary的时候install方法时在Application#onCreate的方法中执行的。
我们首先看isInAnalyzerProcess方法,看注释如果是LeakCanary进程就不允许初始化其他任务。这个进程是为LeakCanary分析堆内存用的。
我们知道引入LeakCanary在你的项目编译成功之后会自动安装一个Leaks apk。看到上面LeakCanary.install(this)这行代码,是不是安装Leaks apk?是不是Leaks通过跨进程来检测我项目呢?检测原理又是怎样的?带着这些问题,接下来看看具体做了什么事情。会调用LeakCanary#install方法
首先我们看看buildAndInstall方法具体做了什么事情
看ActivityRefWatcher类名应该是Activity 引用监控,我们跟进这个installOnIcsPlus方法看看
然后installOnIcsPlus方法又调用了ActivityRefWatcher#watchActivities方法,我们再跟进分析
我们首先看看Application#registerActivityLifecycleCallbacks方法,我们知道原理registerActivityLifecycleCallbacks是注册Activity生命周期回调的方法。管理生命周期的方法,每个Activity都会回调到这里。我们看lifecycleCallbacks这个变量对应着Activity的生命周期。
到这里所以我们是不是可以猜想到LeakCanary其实就是通过注册Activity生命周期回调来监控检查是否有内存泄露的。当Activity界面关闭回调用对应的onActivityDestroyed方法。
接下来我们看看Application.ActivityLifecycleCallbacks#onActivityDestroyed方法干了些什么事情。
接下来会调用到com.squareup.leakcanary.RefWatcher#watch(java.lang.Object)方法。
将其Activity引用包装成一个KeyedWeakReference弱引用。被WeakReference包装的引用如果被回收会添加到ReferenceQueue队列中,WeakReference和ReferenceQueue将在接下来的文章里分析。WeakReference和ReferenceQueue
通过检查ReferenceQueue里的Activity引用来检测是否能够被回收。下面具体看看检测方法:
通过ensureGone这个方法名可以看出应该是确保引用释放的意思。具体看看ensureGone方法做了些什么:
我们主要看removeWeaklyReachableReferences(),gcTrigger.runGc(),heapdumpListener.analyze()这三个方法。
1.通过removeWeaklyReachableReferences移除所有ReferenceQueue队列的WeakReference对象的Activity引用。如果可以回收就直接返回。
2.Activity引用如果通过removeWeaklyReachableReferences还是没有移除就通过gcTrigger.runGc()来GC触发回收。
3.接下来再触发步骤1的removeWeaklyReachableReferences方法来移除Activity引用,判断是否回收,如果可以回收就直接返回,反之就说明对象泄露了就会触发heapdumpListener.analyze()方法来分析,看到HeapDump对象,我们可以通过heapDumper.dumpHeap()方法看到dump当前的heap hprof快照文件。
具体通过Debug.dumpHprofData(heapDumpFile.getAbsolutePath())方法去dump内存文件的。实现如下:
接下来会调用com.squareup.leakcanary.ServiceHeapDumpListener#analyze方法将内存文件目录等相关信息通过HeapAnalyzerService#runAnalysis方法来进行对象内存泄露的分析。实现如下:
接着会启动HeapAnalyzerService IntentService服务。
具体在HeapAnalyzerService#onHandleIntent方法中通过HeapAnalyzer#checkForLeak来检测是否内存泄露的。实现如下:
接下来启动AbstractAnalysisResultService这个IntentService,启动后会调用onHandleIntent方法。
最终通过onHeapAnalyzed这个抽象方法将heapDump,AnalysisResult信息传入到子类实现。
分析上面逻辑其实就是通过DisplayLeakService做内存泄露相关展示。
3.总结
LeakCanary利用Application#registerActivityLifecycleCallbacks Activity生命周期回调onActivityDestroyed方法通过调用RefWatcher#wather方法来检测对象是否回收,通过removeWeaklyReachableReferences—>gcTrigger.runGc—>removeWeaklyReachableReferences—>heapdumpListener.analyze 三步二次检测来确定内存泄露,最终dump 内存信息来分析到最终显示分析出的泄露信息。