手把手带你分析LeanCancary源码

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了手把手带你分析LeanCancary源码相关的知识,希望对你有一定的参考价值。

参考技术A LeakCancary 是一个实时监控内存泄漏的开源框架,当检测到有内存泄漏时,会以通知的方式提示开发者当前发生了内存泄漏

监听activity的生命周期,在Activity的onDestory方法中,开始监听activity对象, 通过将Activity包装到WeakReference中,被WeakReference包装过的Activity对象如果被回收,该WeakReference引用会被放到ReferenceQueue中,通过监测ReferenceQueue里面的内容就能检查到Activity是否能够被回收。其中最重要的两个对象为

Set<String> retainedKeys: 存放所有监控的Activity的key(值为通过uuid,唯一标识Activity)
ReferenceQueue<Object> queue:所有被回收的activity对象会存放到这个引用队列里面, 如果想要知道一个activity有没有内存泄漏,则只需要判断该activity在

1.在build.gradle中添加依赖

至此,LeakCancary 的接入工作就完成了,是不是超简单?

我们从入口函数开始分析

首先判断当前运行的进程是否是属于HeapAnalyzerService进程,如果是 则return调,防止应用本身Application的onCreate方法多次初始化。这里需要这么做的原因是:LeakCancary本身是运行在另外一个进程中的,这点我们可以从LeakCancary的androidManifaset.xml中可以看出是有单独设置process Named的。

接下来执行 LeakCanary.install

LeakCanary.refWatcher()

通过builder模式构建了AndroidRefWatcherBuilder对象,然后通过AndroidRefWatcherBuilder对象设置了listenerServiceClass()用于绑定DisplayLeakService服务,该服务用来分析和显示内存泄漏信息的通知

AndroidRefWatchBuilder.buildAndInstall

先调用AndroidRefWatchBuilder.buid() 构建一个RefWatcher对象

构建RefWatcher的参数有

解析来是

LeakCancaryInternal.java

启动DisplayLeakActivity并显示应用图标,这个图标是LeakCancary这个应用的图标

接下来是执行 :

ActivityRefWatcher.install(context, refWatcher);

在Activity的onDestroy方法中执行RefWatcher.watch(activity)

RefWatcher.java

这里需要注意几个变量:

这里有一个知识点:弱引用和引用队列配合时,当弱引用持有的对象被垃圾回收,java虚拟机会把这个弱引用加入到与之关联的引用队列中。也就是说当activity被回收时,activity对象的引用就会被添加到ReferenceQueue这个引用队列中。

接下来是具体的内存泄漏判断过程

efWatcher.ensureGoneAsync

这里的watchExecutor 实现类是AndroidWatchExecutor

AndroidWatchExecutor.execute()

这里是切换到主线程,当消息队列空闲时执行run方法, run方法实际执行的是RefWatcher中的ensureGone()

RefWatcher.ensureGone();

遍历ReferenceQueue列表中的对象(这些对象已经被回收), 判断对象是否存在当前activity的弱引用,存在则删除retainedKeys中的activity的key 值; 如果activity没有被回收,则不会添加到ReferenceQueue,也就不会从retainedKeys中移除

2.通过gone(reference)来判断当前弱引用对应的Activity是否存在于retainedKeys?如果不存在,则说明通过第一步的操作,已经移除了该引用的key值,直接返回即可。
3.如果第二部没有返回,说明retainedKeys还存在当前activity的引用(也就是改activity没有被添加到ReferenceQueue,没有被回收),则调用GcTigger.runGc方法运行GC.

AndroidHeapDumper.dumpHeap()

调用 File heapDumpFile = leakDirectoryProvider.newHeapDumpFile(); 新建hprof文件,然后调用Debug.dumphprofData() 方法 dump 当前堆内存并写入刚才创建的文件。

然后调用heapdumpListener.analyze(heapDump)分析刚刚生成的heapDumpwen文件

这里的heapdumpListener 是ServiceHeapDumpListener

调用HeapAnalyzerService开始启动HeapAnalyzerService 这个前台服务执行分析

HeapAnalyzerService.java

调用heapAnalyzer.checkForLeak 获取结果后,调用AbstractAnalysisResultService.sendResultToListener展示分析结果。具体是通过DisplayLeakService 来展示的。

最后会执行afterDefaultHandling方法,在这里我们可以自定义一些操作,例如上报泄漏信息给服务器

LeakCancary主要是利用了弱引用 WeakReference 和 引用队列 ReferenceQueue的知识,当WeakReference中引用的对象被回收时,该引用会被添加到ReferenceQueue中,如果没有被回收,则不会添加到ReferenceQueue中。 所以可以通过检测ReferenceQueue是否存在activity的引用来判断activity是否存在泄漏导致没有回收。

LeakCanacary 监控内存泄漏主要流程如下:

参考 https://juejin.im/post/5a9d46d2f265da237d0280a3

以上是关于手把手带你分析LeanCancary源码的主要内容,如果未能解决你的问题,请参考以下文章

Android:手把手带你分析 Protocol Buffer使用 源码

手把手带你阅读Mybatis源码执行篇

手把手带你阅读Mybatis源码缓存篇

手把手带你源码解析HDFS文件上传之create创建过程

手把手带你源码解析HDFS文件上传之create创建过程

别怕,手把手带你撕拉扯下SpringMVC的外衣