美文网首页
LeakCanary浅析

LeakCanary浅析

作者: David_zhou | 来源:发表于2018-03-29 22:12 被阅读8次

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

       源码分析

    1. 注册

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

    构建一个AndroidRefWatcherBuilder的对象。

    而AndroidRefWatcherBuilder继承自RefWatcherBuilder。

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

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

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

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

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

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

    2 检测

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

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

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

    关键代码如下

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

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

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

    接下来回头看ensuregone方法

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

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

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

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

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

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

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

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

    3 总结

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

    ActivityLifecyleCallbacks的使用

    弱引用及referenceQueu的使用

    builder 构造者设计模式

    简单的startservice 跨进程通信

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

    Debug辅助调试类。

    引用

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

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

    相关文章

      网友评论

          本文标题:LeakCanary浅析

          本文链接:https://www.haomeiwen.com/subject/umevcftx.html