一、原理分析
首先在Application中进行初始化操作,进行监听。监听的原理在于 Application 的 registerActivityLifecycleCallbacks 方法,该方法可以对应用内所有 Activity 的生命周期做监听。
|
|
在最后一步buildAndInstall()中实现监听操作。
|
|
在ActivityRefWatcher实现监听,只对onDestory进行了监听处理。
|
|
当一个Activity销毁时,那么就会执行
refWatcher.watch(activity);
接着看
|
|
这里会把待检测的对象构造成KeyedWeakReference
,其实就是WeakReference
,只是添加了key和name.构造时传入ReferenceQueue
,WeakReference
构造函数会传入ReferenceQueue
,当WeakReference指向的对象被垃圾回收时,会把WeakReference放入ReferenceQueue。
在构造时我们需要传入一个ReferenceQueue,这个ReferenceQueue是直接传入了WeakReference中的.
WeakReference源码:
|
|
这里需要明白一件事件,就是为什么每次WeakReference所指向的对象被GC后,这个弱引用都会被放入这个与之相关联的ReferenceQueue队列中。看下源码
|
|
然后进入 ensureGoneAsync(watchStartNanoTime, reference);
进行检测。
|
|
通过Runtime.gc()
和System.runFinalization()
进行GC操作。
System.gc()只在System.runFinalization()后才会调用Runtime().getRuntime().gc()操作。否则在System.runFinalization()才会调用Runtime().getRuntime().gc()操作。
System.runFinalization()调用Runtime().getRuntime().runFinalization()。
由于System.gc()无法保证一定会调用gc,所以LeakCanary直接调用Runtime().getRuntime().gc()。
System类的gc()和runFinalization()
|
|
首先通过removeWeaklyReachableReferences()
手动移除KeyedWeakReference
,具体操作是通过queue.poll()
取出KeyedWeakReference
然后在retainedKeys中移除该KeyedWeakReference
,然后再进行一次gcTrigger.runGc();
操作二次确认retainedKeys
中是否已经移除了key.如果仍然没有移除,那么确定是内存泄漏了,然后进行内存泄漏分析。
二、小结
判断泄漏实现基本步骤
LeakCanary.install()返回了一个RefWatcher。会注册对应用内所有 Activity 生命周期的监听。RefWatcher.queue是一个ReferenceQueue实例。
在Activity销毁时,进行泄漏判断
void onActivityDestroyed(Activity activity) { refWatcher.watch(activity); }
这里会把检测到的 activity 实例关联包装为一个自定义的弱引用(KeyedWeakReference),但是这里在指定弱引用时,LeakCanary 同时还为这个弱引用指定了一个 ReferenceQueue 队列。
通过继承自WeakReference的KeyedWeakReference,增加了key+name字段从而支持对象的唯一起名(通过UUID)和名字获取。
在RefWatcher.watch()时把UUID放入RefWatcher.retainedKeys,并把对象跟RefWatcher.queue关联。
通过Runtime.gc()和System.runFinalization()进行GC操作。
在RefWatcher.removeWeaklyReachableReferences()调用queue.poll()取出KeyedWeakReference,并从retainedKeys中删除。所以,如果retainedKeys中key仍存在,说明对象未被垃圾回收。反之则已经垃圾回收。
如果对象未被垃圾回收,则执行分析