LeakCanary浅析

      说到内存泄漏,就必须提到LeakCanary. 这个利器,很方便的显示出内存泄漏的地方。在用到的过程中好奇怎么做到的,下面跟着网上的博客简单的分析下LeakCanary源码。


   源码分析

1. 注册

使用很简单,关键的一行代码“LeakCanary.install(this)”;下面就以这行代码为线索分析。

LeakCanary浅析_第1张图片

构建一个AndroidRefWatcherBuilder的对象。

而AndroidRefWatcherBuilder继承自RefWatcherBuilder。

创建的实际是子类对象,因此后续调用的都是子类的方法,除非子类不存在,则会调用父类的方法。

而传进去的参数DisplayService.这个类是用于内存泄漏后的展示。

这个是创建那些需要去除的引用,因为有些内存泄漏是已知,且是系统层级的。因此判断是否内存泄漏的时候需要排除。这个也可以手动增加,比如这个类的泄漏不严重,但改起来代价太大,就可以手动将这个类放进去。

LeakCanary浅析_第2张图片

最后调用这个方法,关键的地方在于build()这个方法,通过建造者设计模式设置参数。因为前面创建的是子类对象,因此调用方法时会优先调用子类的方法。另外值得注意的是最后new RefWatcher时,会去创建一个Disabled的父类的对象,也会去调用build()方法。

LeakCanary浅析_第3张图片

enableDisplayLeakActivity 这个用来控制内存泄漏图标的显示与否。

LeakCanary浅析_第4张图片

注册activity的ActivityLifecycleCallbacks. 这样就可以在activity的ondestroy方法中执行内存泄漏的检查。其实可以从此处看出LeakCanary 的缺点,一个是只能检测到activity的内存泄漏,另一个是只能检测非前台的activity的内存泄漏。比如service 的内存泄漏就检测不到。

2 检测

当activity 执行到ondestroy 方法时,会回调ActivityLifecycleCallbacks.

LeakCanary浅析_第5张图片

然后开始进行内存泄漏的检查,一路跟进去关键代码如下:

LeakCanary浅析_第6张图片
LeakCanary浅析_第7张图片

而这个watchExcuter 则是在最开始install 的时候通过builder 方法创建。实际如下

LeakCanary浅析_第8张图片

关键代码如下

LeakCanary浅析_第9张图片

Retryable 实际上是一个runnable对象。可以看到execute的retryable,最后都会在主进程中执行。

而MessageQueue.IdleHandler可以用来在线程空闲的时候,指定一个操作,使用IdleHandler的好处在于可以不用指定一个将来时间,只要线程空闲了,就可以执行它指定的操作。

这个是界面跳转后内存泄漏的检查需要稍等下的原因之一。另外一个原因可能是生成分析dump文件比较费时。

接下来回头看ensuregone方法

LeakCanary浅析_第10张图片

removeWeaklyReachableReferences方法会需要试着移除弱引用,如果移除后的集合中不包括activity的引用对象。则说明没有泄漏,否则就需要手动gc, 然后通过removeWeaklyReachableReferences检查gc后 。如果此时集合中还有activity对应的引用对象,就说明内存泄漏了。否则就不认为发生内存泄漏。如果发生内存泄漏,接下来就需要检测出到底什么地方发生了泄漏。

LeakCanary浅析_第11张图片

此时的heapDumper也是最开始install的时候通过build()方法构造的。

LeakCanary浅析_第12张图片

这个地方是调用的系统的Debug类的dumpHprofData,来生成dump文件,文件名就是传进去的参数。值得深挖的是Debug这个类,有很多有用的帮助调试的方法。

生成文件之后 然后会走到heapDumpListener。通过analyze 开始正式对dump文件分析。

然后就调到HeapAnalyzerService的runAnalysis方法。HeapAnalyzerService是一个intentservice类,执行结束,这个service会自动销毁。然后runAnalysis调用到onHandleIntent 方法中去。需要注意的是,因为HeapAnalyzerService在manifest中是标记的另外的进程,所以此处虽然是startservice,这样启动service,但启动的service 运行在新的进程中。

LeakCanary浅析_第13张图片

HeapAnalyzer会使用checkForLeak的方法来分析内存泄露结果。

LeakCanary浅析_第14张图片
LeakCanary浅析_第15张图片

这里又个值得注意的地方是,老版本的LeakCanary使用的是eclipse.mat 这个包来分析的。而新版本的则是使用的squaredup的haha库。

LeakCanary浅析_第16张图片

此处也是跨进程调用的。然后结果就会传给最开始的displayleakservice。然后就会发通知到通知栏。然后开发者就可以很方便的点进去看到相关的内存泄漏了。

3 总结

一路下来,代码并不是很难,不过多看几遍就会有收获的。有如下知识点:

ActivityLifecyleCallbacks的使用

弱引用及referenceQueu的使用

builder 构造者设计模式

简单的startservice 跨进程通信

MessageQueue.IdleHandler可以用来在线程空闲的时候,指定一个操作

Debug辅助调试类。


引用

https://www.jianshu.com/p/481775d198f0

这篇文章讲的很好,基本上就是自己想说的,截图什么的都是来自这篇文章。感谢分享。

你可能感兴趣的:(LeakCanary浅析)