前言
LeakCanary 是 Square 公司为 Android 开发者提供的一个自动检测内存泄漏的工具,在4月23日推出了2.0预览版,更新内容见 Github,其中新增了一个 LeakSentry 库,该库作为 LeakCanary 的开关,可以实时查看那些被观察的对象是否可能内存泄露,并且可以独立引入使用,下面从源码角度来分析下该库,本文基于 2.0-alpha-2。
源码分析
LeakSentryInstaller.onCreate
首先查看其 manifest 文件,发现其中注册了一个名叫 LeakSentryInstaller 的 ContentProvider,因此其onCreate 方法会在 Application.onCreate 之前得到执行,原因如下:
// ActivityThread.java |
搞清楚了入口以后,看看 LeakSentryInstaller.onCreate 都干了些什么。
// LeakSentryInstaller.kt |
onCreate 内部调用了 InternalLeakSentry.install,在其 init 代码块设置了监听器当 LeakCanary 被依赖时会设置成 InternalLeakCanary 实例,不然就是一个空实现,install 内部主要就是调用了两个 Watch.install。
ActivityDestroyWatcher.install
代码如下:
// ActivityDestroyWatcher.kt |
内部注册了一个 Activity 生命周期回调,当 onDestory 事件来临时由于默认的 config.watchActivities = true ,因此 refWatcher.watch 将被调用。
class RefWatcher constructor( |
watch 方法主要分为如下几步:
- 当 isEnabled 被设置成 false (release 包),那么 watch 将会直接返回,该值取自于 config 。
- 移除掉那些已经在队列里面的弱引用,一开始肯定没有先跳过。
- 创建一个 KeyedWeakReference 实例将观察对象这里是 onDestroy 后的 Activity 实例,传入 queue,当被观察的对象被回收掉以后会将弱引用对象放入该队列中去。
- 将弱引用对象放入 watchedReferences 中。
- 延迟一定时间后(默认为5秒,取自于config)调用 moveToRetained。
moveToRetained 方法主要分为如下几步:
- 首先调用了 removeWeaklyReachableReferences ,该方法将那些已经放到队列中的弱引用对象从 watchedReferences 中移除(存在队列中就表示该对象已经被回收了不可能发生内存泄露),后面的retainedReferences.remove 是为了将上次保留的对象删除(因为本次它已经被回收了)。
- 接着如果 retainedRef!=null,那么就说明当前对象还没有被回收,就加入到 retainedReferences 中,并回调listener.onReferenceRetained。
方法主要是统计哪些应该要被回收的对象,但是却还没有被回收。
注:retainedReferences 保存经过检查还没被回收的对象,watchedReference 保存正在检测的对象。
FragmentDestroyWatcher.install
代码如下:
internal interface FragmentDestroyWatcher { |
首先 FragmentDestroyWatcher 只支持 Android8 及以上或者是 AndroidX ,还是监听了 Activity 生命周期不过这次监听 onCreate,先看看 AndroidOFragmentDestroyWatcher.watchFragments。
AndroidOFragmentDestroyWatcher.watchFragments
代码如下:
internal class AndroidOFragmentDestroyWatcher( |
内部注册了 Fragment 声明周期回调,由于该方法只有在 API26 及以上才有,因此前面判断了 Android O,接着当 Fragment 被销毁后会分别调用 refWatcher.watch(view)、refWatcher.watch(fragment),这里面的逻辑上文已经说过了。
SupportFragmentDestroyWatcher#watchFragments
代码如下:
internal class SupportFragmentDestroyWatcher( |
内部逻辑与 AndroidOFragmentDestroyWatche r一样,只是获取的是 supportFragmentManager。
总结
根据源码可以看出 LeakSentry 内部使用弱引用保存被观察对象,在指定时间后如果还未被回收就可以认为该对象可能发生内存泄露,其默认会自动观察销毁的 Activity、fragment 及其内部 View,同时也可以手动使用 LeakSentry.refWatcher.watch(obj)
来观察任意不再需要的对象,然后在代码中通过调用 LeakSentry.refWatcher.retainedKeys.size
查看还有几个被观察对象还未被释放。