LeakCanary是一款开源的内存泄漏检查工具
核心代码及原理
通过registerActivityLifecycleCallbacks来监听Activity Fragment 的生命周期:
onActivityDestroyed方法最终会调用RefWatcher.watch方法:
其实后面的版本已经增加方法能够添加任何有生命周期的对象的监听,RefWatch.watch(instance)
比如service的destroy也可以调用上述方法。
监测机制利用了Java的WeakReference和ReferenceQueue,通过将Activity包装到WeakReference中,被WeakReference包装过的Activity对象如果被回收,该WeakReference引用会被放到ReferenceQueue中,通过监测ReferenceQueue里面的内容就能检查到Activity是否能够被回收
1、 首先通过removeWeaklyReachablereference来移除已经被回收的Activity引用
QQ图片20190428150305.png
2、 通过gone(reference)判断当前弱引用对应的Activity是否已经被回收,如果已经回收说明activity能够被GC,直接返回即可。
QQ图片20190428150426.png下面两张图是说明用set来保存一个弱引用的key值,它是如何生成和绑定的就是set<key>
weakReference queue的三者关系。
public void watch(Object watchedReference, String referenceName) {
if (this == DISABLED) {
return;
}
checkNotNull(watchedReference, "watchedReference");
checkNotNull(referenceName, "referenceName");
final long watchStartNanoTime = System.nanoTime();
String key = UUID.randomUUID().toString();
retainedKeys.add(key);
final KeyedWeakReference reference =
new KeyedWeakReference(watchedReference, key, referenceName, queue);
ensureGoneAsync(watchStartNanoTime, reference);
}
3、 如果Activity没有被回收,调用GcTigger.runGc方法运行GC,GC完成后在运行第1步,然后运行第2步判断Activity是否被回收了,如果这时候还没有被回收,那就说明Activity可能已经泄露。
QQ图片20190428150539.png
4、 如果Activity泄露了,就抓取内存dump文件(Debug.dumpHprofData)到本地,给haha库分析,排除一些误检查内存泄露信息,并找出gcroot的最短路径,然后显示出来。
5、后面新版的leak,可以支持线上版本的监听,不会影响app性能,使用leakSentry,原理是在watchedReferences 的key里面是不是已经在ReferenceQueue里面,在的话说明已经回收了,如果没有把这个watchedReferences 移动到retainedReferences,然后就粗略的认为是已经泄露了,没有手动GC,也没有dump hprof,没有分析过程,这些都是会影响性能的。
网友评论