leakcanary2.x 源码解析
一、导读
在阅读源码前,请大家思考以下几个问题
1.它是如何做到仅一行配置代码就完成监控的,接入leakcanary并没有写任何代码,它是如何运行起来的?
2.它是在什么时机,去判断是否存在内存泄露的
3.它是通过什么原理,来判断是否存在内存泄露的
二、源码解析
2.1 接入
dependencies {
...接入方式
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.3'
}
<application>
...
//解压apk,看到接入新版本的LeakCanary的Manifest文件中生成了如下的provider
<provider
android:name="leakcanary.internal.AppWatcherInstaller$MainProcess"
android:exported="false"
<!-- SDK类可以学习这种占位符的方式,降低接入方的接入成本-->
<!-- android:authorities="${applicationId}.leakcanary-installer"-->
android:authorities="com.vivo.website.gdpr.leakcanary-installer" />
</application>
知识点:
1.ContentProvider的onCreate的调用时机是在application onCreate之前调用的,即在应用启动时,完成了自身代码的调用,降低了接入方在java代码层面上的接入成本
2.通过占位符的方式,简化了接入方在manifest文件上的接入成本
3.debugImplementation 仅在debug模式下生效,降低了使用implementation时需要依赖空包的接入成本
2.2 监控时机
internal sealed class AppWatcherInstaller : ContentProvider() {
//provider的onC方法中,调用了install方法
override fun onCreate(): Boolean {
val application = context!!.applicationContext as Application
InternalAppWatcher.install(application)
return true
}
}
知识点:现在一些新的组件,都由java代码切到了kotlin 上来,对于还未学习kotlin的同学来说,在AS中,可以通过查看对应类的class文件,反编译为java查看
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iuxM1Aim-1594300470721)(C:\Users\11070535\AppData\Roaming\Typora\typora-user-images\1592035574741.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SWag20Uq-1594300470723)(C:\Users\11070535\AppData\Roaming\Typora\typora-user-images\1592035595332.png)]
internal object InternalAppWatcher {
//...
fun install(application: Application) {
SharkLog.logger = DefaultCanaryLog()
checkMainThread()
if (this::application.isInitialized) {
return
}
InternalAppWatcher.application = application
val configProvider = { AppWatcher.config }
// 监控activity的内存泄漏
ActivityDestroyWatcher.install(application, objectWatcher, configProvider)
// 监控fragment的内存泄漏
FragmentDestroyWatcher.install(application, objectWatcher, configProvider)
onAppWatcherInstalled(application)
}
//...
}
2.2.1Activity的内存泄露监测
internal class ActivityDestroyWatcher private constructor(
private val objectWatcher: ObjectWatcher,
private val configProvider: () -> Config
) {
//
private val lifecycleCallbacks =
object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
//activity destory 的时候,对Activity watch
override fun onActivityDestroyed(activity: Activity) {
if (configProvider().watchActivities) {
objectWatcher.watch(
activity, "${activity::class.java.name} received Activity#onDestroy() callback"
)
}
}
}
companion object {
fun install(application: Application, objectWatcher: ObjectWatcher,
configProvider: () -> Config
) {
val activityDestroyWatcher =ActivityDestroyWatcher(objectWatcher, configProvider)
//在application中注册 ActivityLifecycleCallbacks
application.registerActivityLifecycleCallbacks(activityDestroyWatcher.lifecycleCallbacks)
}
}
}
**监控activity:**主要通过在Application中注册registerActivityLifecycleCallbacks绑定Activity生命周期回调,并在Activity destory时,调用ObjectWatcher的watch方法进行检测,ObjectWatcher会在稍后讲到
2.2.2 Fragment的内存泄露监测
//internal object FragmentDestroyWatcher
fun install(
application: Application,
objectWatcher: ObjectWatcher,
configProvider: () -> AppWatcher.Config
) {
val fragmentDestroyWatchers = mutableListOf<(Activity) -> Unit>()
if (SDK_INT >= O) {
// 添加对android.app.Fragment的支持
fragmentDestroyWatchers.add(
AndroidOFragmentDestroyWatcher(objectWatcher, configProvider)
)
}
// 如果使用了AndroidX库,添加对androidx.fragment.app.Fragment的支持,同时支持了viewmodel
getWatcherIfAvailable(
ANDROIDX_FRAGMENT_CLASS_NAME,
ANDROIDX_FRAGMENT_DESTROY_WATCHER_CLASS_NAME,
objectWatcher,
configProvider
)?.let {
fragmentDestroyWatchers.add(it)
}
// 如果使用support库,添加对support.v4.app.Fragment的支持
getWatcherIfAvailable(
ANDROID_SUPPORT_FRAGMENT_CLASS_NAME,
ANDROID_SUPPORT_FRAGMENT_DESTROY_WATCHER_CLASS_NAME,
objectWatcher,
configProvider
)?.let {
fragmentDestroyWatchers.add(it)
}
if (fragmentDestroyWatchers.size == 0) {
return
}
// 注册Activity生命周期监听
application.registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
override fun onActivityCreated(
activity: Activity,
savedInstanceState: Bundle?
) {
// 在onActivityCreated回调中,依次对各Watcher进行初始化
for (watcher in fragmentDestroyWatchers) {
watcher(activity)
}
}
})
}
fragment 比较特殊,LeakCanary针对android.app.Fragment 、support.v4.app.Fragment、androidx.fragment.app.Fragment 三种fragment,分别通过AndroidOFragmentDestroyWatcher、AndroidSupportFragmentDestroyWatcherAndroidXFragmentDestroyWatcher来进行监听支持
//internal class AndroidOFragmentDestroyWatcher(
private val fragmentLifecycleCallbacks = object : FragmentManager.FragmentLifecycleCallbacks() {
override fun onFragmentViewDestroyed(
fm: FragmentManager,
fragment: Fragment
) {
val view = fragment.view
if (view != null && configProvider().watchFragmentViews) {
objectWatcher.watch(
view, "${fragment::class.java.name} received Fragment#onDestroyView() callback " +
"(references to its views should be cleared to prevent leaks)"
)
}
}
override fun onFragmentDestroyed(
fm: FragmentManager,
fragment: Fragment
) {
if (configProvider().watchFragments) {
objectWatcher.watch(
fragment, "${fragment::class.java.name} received Fragment#onDestroy() callback"
)
}
}
}
override fun invoke(activity: Activity) {
val fragmentManager = activity.fragmentManager
fragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true)
}
监控android.app.Fragment:AndroidOFragmentDestroyWatcher类中,主要通过在Activity中注册注册FragmentLifecycleCallbacks回调,
当触发onFragmentViewDestroyed回调时,通过ObjectWatcher#watch检查fragment.mView对象(即Fragment#onCreateView创建的View)。
当触发onFragmentDestroyed回调时,检查fragment对象是否泄漏。
internal class AndroidXFragmentDestroyWatcher(
private val objectWatcher: ObjectWatcher,
private val configProvider: () -> Config
) : (Activity) -> Unit {
private val fragmentLifecycleCallbacks = object : FragmentManager.FragmentLifecycleCallbacks() {
override fun onFragmentCreated(
fm: FragmentManager,
fragment: Fragment,
savedInstanceState: Bundle?
) {
ViewModelClearedWatcher.install(fragment, objectWatcher, configProvider)
}
override fun onFragmentViewDestroyed(
fm: FragmentManager,
fragment: Fragment
) {
val view = fragment.view
if (view != null && configProvider().watchFragmentViews) {
objectWatcher.watch(
view, "${fragment::class.java.name} received Fragment#onDestroyView() callback " +
"(references to its views should be cleared to prevent leaks)"
)
}
}
override fun onFragmentDestroyed(
fm: FragmentManager,
fragment: Fragment
) {
if (configProvider().watchFragments) {
objectWatcher.watch(
fragment, "${fragment::class.java.name} received Fragment#onDestroy() callback"
)
}
}
}
override fun invoke(activity: Activity) {
if (activity is FragmentActivity) {
val supportFragmentManager = activity.supportFragmentManager
supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true)
ViewModelClearedWatcher.install(activity, objectWatcher, configProvider)
}
}
}
监控androidx.fragment.app.Fragment:AndroidXFragmentDestroyWatcherr类中,主要通过在Activity中注册supportFragmentManager注册LifecycleCallbacks监听Fragment生命周期。
同android Fragment的监听一样,在onFragmentViewDestroyed检测View,在onFragmentDestroyed检测Fragment。
有一点不同的是,AndroidXFragmentDestroyWatcher在onFragmentCreated回调中,还会初始化ViewModel的监听。当ViewModel执行clear触发onCleared回调时,会检测ViewModel是否泄漏。
internal class AndroidSupportFragmentDestroyWatcher(
private val objectWatcher: ObjectWatcher,
private val configProvider: () -> Config
) : (Activity) -> Unit {
private val fragmentLifecycleCallbacks = object : FragmentManager.FragmentLifecycleCallbacks() {
override fun onFragmentViewDestroyed(
fm: FragmentManager,
fragment: Fragment
) {
val view = fragment.view
if (view != null && configProvider().watchFragmentViews) {
objectWatcher.watch(
view, "${fragment::class.java.name} received Fragment#onDestroyView() callback " +
"(references to its views should be cleared to prevent leaks)"
)
}
}
override fun onFragmentDestroyed(
fm: FragmentManager,
fragment: Fragment
) {
if (configProvider().watchFragments) {
objectWatcher.watch(
fragment, "${fragment::class.java.name} received Fragment#onDestroy() callback"
)
}
}
}
override fun invoke(activity: Activity) {
if (activity is FragmentActivity) {
val supportFragmentManager = activity.supportFragmentManager
supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true)
}
}
}
监控support.v4.app.Fragment:AndroidSupportFragmentDestroyWatcher类中
同android Fragment的监听一样,在onFragmentViewDestroyed检测View,在onFragmentDestroyed检测Fragment。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X4v1d9JL-1594300470727)(C:\Users\11070535\AppData\Roaming\Typora\typora-user-images\1591758151988.png)]
经过上面对源码的跟进,想必大家应该理解了上面这段话,上述的源码,刚好已经实现了对这些内容的监控
2.3、监控原理
从上面对Activity和fragment 的监控情况来看,所有的内存泄露的监控,最终都调用到了ObjectWatcher对象的watch方法,该方法,才是实现监控内存泄露的核心方法,接下来,让我们一起看下ObjectWatcher的核心实现
class ObjectWatcher constructor(
private val clock: Clock,
private val checkRetainedExecutor: Executor,
/**
* References passed to [watch].
* 正在被观察的对象,此时还未泄漏
*/
private val watchedObjects = mutableMapOf<String, KeyedWeakReference>()
//引用队列 配合弱引用 定位泄漏的对象。
private val queue = ReferenceQueue<Any>()
//泄漏监听
private val onObjectRetainedListeners = mutableSetOf<OnObjectRetainedListener>()
/**
* Watches the provided [watchedObject].
*
* @param description Describes why the object is watched.
*/
@Synchronized fun watch(
watchedObject: Any,
description: String
) {
if (!isEnabled()) {
return
}
//清除watchedObjects中不存在泄露的弱引用对象
removeWeaklyReachableObjects()
val key = UUID.randomUUID()
.toString()
val watchUptimeMillis = clock.uptimeMillis()
val reference =
KeyedWeakReference(watchedObject, key, description, watchUptimeMillis, queue)
SharkLog.d {
"Watching " +
(if (watchedObject is Class<*>) watchedObject.toString() else "instance of ${watchedObject.javaClass.name}") +
(if (description.isNotEmpty()) " ($description)" else "") +
" with key $key"
}
//将本次watch的对象加入到watchedObjects 的map中
watchedObjects[key] = reference
//通过checkRetainedExecutor,5秒后执行moveToRetained
checkRetainedExecutor.execute {
//若依旧存在引用,则通知onObjectRetainedListeners
moveToRetained(key)
}
}
@Synchronized private fun moveToRetained(key: String) {
//清除无需观察的对象
removeWeaklyReachableObjects()
//通过key 去找引用,若存在引用,这证明5后,本该回收的对象未能回收,可能存在内存泄露
val retainedRef = watchedObjects[key]
if (retainedRef != null) {
retainedRef.retainedUptimeMillis = clock.uptimeMillis()
onObjectRetainedListeners.forEach { it.onObjectRetained() }
}
}
private fun removeWeaklyReachableObjects() {
// WeakReferences are enqueued as soon as the object to which they point to becomes weakly
// reachable. This is before finalization or garbage collection has actually happened.
//queue是一个 ReferenceQueue队列,当一个对象被GC掉之后,会被加入到这个队列当中,即queue中存在的对象,都可以认为是不会存在内存泄露的对象
var ref: KeyedWeakReference?
do {
ref = queue.poll() as KeyedWeakReference?
if (ref != null) {
watchedObjects.remove(ref.key)
}
} while (ref != null)
}
}
**知识点:**WeakReference创建时,可以传入一个ReferenceQueue对象,假如WeakReference中引用对象被回收,那么就会把WeakReference对象添加到ReferenceQueue中,可以通过ReferenceQueue中是否为空来判断,被引用对象是否被回收
步骤:
1.向watchedObjects添加需要watch的对象
2.removeWeaklyReachableObjects方法使用WeakReference+ReferenceQueue的原理,不断的从watchedObjects 的map 中删除已经被释放,不会存在内存泄露的对象
3.checkRetainedExecutor 五秒后执行 moveToRetained方法
4.moveToRetained方法则在一直寻找依旧存在与watchedObjects 中的对象,存在,即代表有内存泄露
5.通知泄露
//InternalAppWatcher类中,checkRetainedExecutor的实现方式如下5s后执行
/**
* How long to wait before reporting a watched object as retained.
*
* Default to 5 seconds.
*/
val watchDurationMillis: Long = TimeUnit.SECONDS.toMillis(5)
private val checkRetainedExecutor = Executor {
mainHandler.postDelayed(it, AppWatcher.config.watchDurationMillis)
}
val objectWatcher = ObjectWatcher(
clock = clock,
checkRetainedExecutor = checkRetainedExecutor,
isEnabled = { AppWatcher.config.enabled }
)
//InternalLeakCanary类中实现onObjectRetainedListeners的回调
override fun onObjectRetained() {
if (this::heapDumpTrigger.isInitialized) {
//后续的堆栈打印相关事宜
heapDumpTrigger.onObjectRetained()
}
}
通过上面的流程,想必,大家对这个方法的应用,也有了一定的理解
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Aigm1XxH-1594300470733)(C:\Users\11070535\AppData\Roaming\Typora\typora-user-images\1591758705567.png)]
三、总结
3.1.它是如何做到仅一行配置代码就完成监控的
1.ContentProvider的onCreate的调用时机是在application onCreate之前调用的,即在应用启动时,完成了自身代码的调用,降低了接入方在java代码层面上的接入成本
2.通过占位符的方式,简化了接入方在manifest文件上的接入成本
3.debugImplementation 仅在debug模式下生效,降低了使用implementation时需要依赖空包的接入成本
3.2 它是在什么时机,去判断是否存在内存泄露的
1.Activity:通过在Application中注册registerActivityLifecycleCallbacks绑定Activity生命周期回调,并在onActivityDestroyed回调中监控Activity
2.Fragment:通过在Application中注册registerActivityLifecycleCallbacks绑定Activity生命周期回调,并在onActivityCreated回调中,通过在Activity中注册注册FragmentLifecycleCallbacks回调,并在onFragmentDestroyed回调时,监控fragment
3.Fragment View:通过在Application中注册registerActivityLifecycleCallbacks绑定Activity生命周期回调,并在onActivityCreated回调中,通过在Activity中注册注册FragmentLifecycleCallbacks回调,并在onFragmentViewDestroyed回调中监控Fragment View
4. ViewModel:针对AndroidX库中的Activity,对于Activit,在onActivityCreated回调中注册监听,对于Fragment,在onFragmentCreated回调中注册监听,,,在ViewModel的onCleared回调中监控ViewModel
3.3 它是通过什么原理,来判断是否存在内存泄露的
是利用了WeakRefrence + RefrenceQueue的机制(仅被弱引用持有的对象,当对象被回收时,会存入到引用队列中),从引用队列中不断的获取对象,将已确认被GC的对象剔除,剩余未被回收的对象则定义为可能泄露的对象,当达到一定的判断条件时,通知用户内存泄露
四、流程图
4.1总流程图
[外链图片转存中…(img-UoXYsJ3v-1594300470734)]
4.2 详细流程图
[外链图片转存中…(img-mxGmkP3S-1594300470735)]