1、引入
debugCompile ‘com.squareup.leakcanary:leakcanary-android:1.6.1’
releaseCompile ‘com.squareup.leakcanary:leakcanary-android-no-op:1.6.1’
2、使用
LeakCanary.install(this);
3、原理
LeakCanay的入口是在application的onCreate()方法中声明的,其实用的就是Application的ActivityLifecycleCallbacks回调接口监听所有activity的onDestory()的,在这个方法进行RefWatcher.watch对这个对象进行监控。
具体是这样做的,封装成带key的弱引用对象,然后GC看弱引用对象有没有回收,没有回收的话就怀疑是泄漏了,需要二次确认。然后生成HPROF文件,分析这个快照文件有没有存在带这个key值的泄漏对象,如果没有,那么没有泄漏,否则找出最短路径,打印给我们,我们就能够找到这个泄漏对象了。
4、 源码分析
public static RefWatcher install(Application application) {
return refWatcher(application).listenerServiceClass(DisplayLeakService.class)
.excludedRefs(AndroidExcludedRefs.createAppDefaults().build())
.buildAndInstall();
}
public RefWatcher buildAndInstall() {
RefWatcher refWatcher = build();
if (refWatcher != DISABLED) {
LeakCanary.enableDisplayLeakActivity(context);
ActivityRefWatcher.installOnIcsPlus((Application) context, refWatcher);
}
return refWatcher;
}
installOnIcsPlus-> ActivityRefWatcher-> registerActivityLifecycleCallbacks
用了Application的ActivityLifecycleCallbacks回调接口中的onDestory()回调实现对项目中的activity进行对象监听,然后交给RefWatcher监听类进行进一步处理。
紧接着在RefWatcher. Watch中把activity对象封装成带key值和带引用队列(ReferenceQueue)的KeyedWeakReference对象,key值是用来最终定位泄漏对象用的,第三部分会用到,引用队列是用来监控弱引用回收的,这个类是继承WeakReference类,所以封装完你会看到这个类的一些特点:
1)带key,通过UUID.randomUUID().toString(),是唯一key序列
2)包装成WeakReference并添加到ReferenceQueue
之后呢,封装完成就要开始分析了,核心方法是ensureGone,同时也是LeakCanay的核心所在。
如果这个对象作为弱引用,被回收了,那么添加到引用队列(ReferenceQueue)当中去,所以这个函数.poll是出栈的意思,如果成功出栈了,那么说明你加入了引用队列,然后可以认为是已经被回收了的,然后retainedKeys这个是一个Set容器,在之前会加入生成的唯一key作为标识,这里如果这个对象回收了,那么就移除这个key值。
然后是gone函数,就是看retainedKeys容器有没有key,如果回收了,就不存在key了,那么就没有泄漏,否则就怀疑有泄漏。
然后后面的手动GC和检查都是一个类似二次确认的道理,还是没有回收,那么才会进入精确阶段,.hropf分析大法,这是第三部分内容。
总结:怀疑该对象有没有泄漏,需要经过两部走,RefWatcher封装了非常核心的方法,把对象封装成WeakReference,并执行GC回收,如果存在强引用,那么会无法回收,就会认为有内存泄漏的可能了,然后才会快照分析发。