LeakCanary 源码阅读笔记(一)
LeakCanary
可以探测 Android
应用程序在运行时是否发生了内存泄漏,只能够用在 Debug
的应用上,他和 OkHttp
一样都是出之 Square
公司之手。学习 LeakCanary
的源码对理解 Android
的泄漏和内存 Dump
有非常大的帮助,要学习写代码,就学一流的代码,不说废话了,开始 LeakCanary
的源码学习。
LeakCanary 初始化
LeakCanary
不需要手动写代码初始化,只需要在 gradle
中添加依赖就好了,然后 App
在启动时就会自动运行,年轻的时候我也非常好奇是怎么实现的,其实就是通过 ContentProvider
实现的,它可能是存在感最低的四大组建,但是 ContentProvider
他有一个特点,在 App
初始化的过程中也会初始化 ContentProvider
,这部分代码我就不细说了,感兴趣的同学可去网上找找相关的资料。
LeakCanary
对应的初始化的 ContentProvider
是 MainProcessAppWatcherInstaller
, 对应的 manifest
配置如下:
<application>
<provider
android:name="leakcanary.internal.MainProcessAppWatcherInstaller"
android:authorities="${applicationId}.leakcanary-installer"
android:enabled="@bool/leak_canary_watcher_auto_install"
android:exported="false"/>
</application>
然后我们再看看 MainProcessAppWatcherInstaller
的源码:
internal class MainProcessAppWatcherInstaller : ContentProvider() {
override fun onCreate(): Boolean {
val application = context!!.applicationContext as Application
AppWatcher.manualInstall(application)
return true
}
override fun query(
uri: Uri,
projectionArg: Array<String>?,
selection: String?,
selectionArgs: Array<String>?,
sortOrder: String?
): Cursor? = null
override fun getType(uri: Uri): String? = null
override fun insert(uri: Uri, contentValues: ContentValues?): Uri? = null
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int = 0
override fun update(
uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array<out String>?
): Int = 0
}
在启动的时候调用了 AppWatcher#manualInstall()
方法,其他的都是模版代码。
继续看看 AppWatcher#manualInstall()
方法的实现:
@JvmOverloads
fun manualInstall(
application: Application,
retainedDelayMillis: Long = TimeUnit.SECONDS.toMillis(5),
// 默认的 Watchers
watchersToInstall: List<InstallableWatcher> = appDefaultWatchers(application)
) {
// 检查必须在主线程
checkMainThread()
if (isInstalled) {
throw IllegalStateException(
"AppWatcher already installed, see exception cause for prior install call", installCause
)
}
check(retainedDelayMillis >= 0) {
"retainedDelayMillis $retainedDelayMillis must be at least 0 ms"
}
this.retainedDelayMillis = retainedDelayMillis
if (application.isDebuggableBuild) {
LogcatSharkLog.install()
}
// 初始化 LeakCanaryDelegate,这个对象非常重要
// Requires AppWatcher.objectWatcher to be set
LeakCanaryDelegate.loadLeakCanary(application)
// 安装每个 Watcher
watchersToInstall.forEach {
it.install()
}
// Only install after we're fully done with init.
installCause = RuntimeException("manualInstall() first called here")
}
AppWatcher#manualInstall()
主要初始化两个东西:一个是 LeakCanaryDelegate
;另外一个是各种 Watcher
。Watcher
就是用来监控各种已经进入 destroy
生命周期的 Android
组件;当 Watcher
发现组建已经 destory
了,但是它所对应的 Java
实例并没有被销毁就表示当前已经出现了泄漏,Watcher
就会通知 LeakCanaryDelegate
去 dump
内存,并分析内存,找到泄漏对象的 gc root
,锁定导致对象泄漏的真正凶手。
本篇文章主要分析 Watchers
,后面再分析 LeakCanaryDelegate
。
通过 appDefaultWatchers()
方法获取默认的 Watchers
:
fun appDefaultWatchers(
application: Application,
deletableObjectReporter: DeletableObjectReporter = objectWatcher.asDeletableObjectReporter()
): List<InstallableWatcher> {
// Use app context resources to avoid NotFoundException
// https://github.com/square/leakcanary/issues/2137
val resources = application.resources
val watchDismissedDialogs = resources.getBoolean(R.bool.leak_canary_watcher_watch_dismissed_dialogs)
return listOf(
ActivityWatcher(application, deletableObjectReporter),
FragmentAndViewModelWatcher(application, deletableObjectReporter),
RootViewWatcher(deletableObjectReporter, WindowTypeFilter(watchDismissedDialogs)),
ServiceWatcher(deletableObjectReporter)
)
}
分别包含以下几种 Watchers
:
ActivityWatcher
:监控Activity
的销毁FragmentAndViewModelWatcher
:监控Fragment
和ViewModel
的销毁RootViewWatcher
:监控Window
中的RootView
的销毁ServiceWatcher
:监控Service
的销毁
Watcher
会把已经处于 destroy
的组件通知 DeletableObjectReporter
,后面我们再分析这个对象。
我们先分析各种功能的 Watchers
。
监控 Activity 的销毁
我们直接看 ActivityWatcher
源码:
class ActivityWatcher(
private val application: Application,
private val deletableObjectReporter: DeletableObjectReporter
) : InstallableWatcher {
// Kept for backward compatibility.
constructor(
application: Application,
reachabilityWatcher: ReachabilityWatcher
) : this(application, reachabilityWatcher.asDeletableObjectReporter())
private val lifecycleCallbacks =
object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
override fun onActivityDestroyed(activity: Activity) {
deletableObjectReporter.expectDeletionFor(
activity, "${activity::class.java.name} received Activity#onDestroy() callback"
)
}
}
override fun install() {
application.registerActivityLifecycleCallbacks(lifecycleCallbacks)
}
override fun uninstall() {
application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks)
}
}
因为 Android
本身就提供了监控 Activity
的生命周期的方法,所以上面的代码实现非常简单,当 Activity
destroy
后会通知 DeletableObjectReporter#expectDeletionFor()
方法,所有的组件销毁后都会调用这个方法。这里还有一个非常有意思的点就是通过 noOpDelegate()
方法干掉了 Java
中接口中需要强制实现的方法,我前面写文章介绍过:Kotlin 干掉接口需要强制实现的方法
监控 Fragment 和 ViewModel 的销毁
直接看 FragmentAndViewModelWatcher#install()
方法:
// ...
private val lifecycleCallbacks =
object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
override fun onActivityCreated(
activity: Activity,
savedInstanceState: Bundle?
) {
for (watcher in fragmentDestroyWatchers) {
watcher(activity)
}
}
}
override fun install() {
application.registerActivityLifecycleCallbacks(lifecycleCallbacks)
}
// ...
监听 Activity
的生命周期,当 Activity
创建时依次通知 fragmentDestroyWatchers
,我们来看看 fragmentDestroyWatchers
的实现:
private val fragmentDestroyWatchers: List<(Activity) -> Unit> = run {
val fragmentDestroyWatchers = mutableListOf<(Activity) -> Unit>()
// Android 系统默认的 Fragment Watcher
if (SDK_INT >= O) {
fragmentDestroyWatchers.add(
AndroidOFragmentDestroyWatcher(deletableObjectReporter)
)
}
// Androidx 的 Fragment Watcher
getWatcherIfAvailable(
ANDROIDX_FRAGMENT_CLASS_NAME,
ANDROIDX_FRAGMENT_DESTROY_WATCHER_CLASS_NAME,
deletableObjectReporter
)?.let {
fragmentDestroyWatchers.add(it)
}
// TODO turn this off by default.
// Support 的 Fragment Watcher.
getWatcherIfAvailable(
ANDROID_SUPPORT_FRAGMENT_CLASS_NAME,
ANDROID_SUPPORT_FRAGMENT_DESTROY_WATCHER_CLASS_NAME,
deletableObjectReporter
)?.let {
fragmentDestroyWatchers.add(it)
}
fragmentDestroyWatchers
}
fragment
的监控分为三种,系统的 fragment
,androidx
的 fragment
和 support
的 fragment
,我们只分析 androidx
的 fragment
就好,其他两种大家自行分析。
androidx
的 fragment
的监控类是 AndroidXFragmentDestroyWatcher
,我们来看看它的入口函数:
override fun invoke(activity: Activity) {
if (activity is FragmentActivity) {
val supportFragmentManager = activity.supportFragmentManager
//监控 Fragment 销毁
supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true)
// 监控 ViewModel 销毁
ViewModelClearedWatcher.install(activity, deletableObjectReporter)
}
}
这里分为两块儿逻辑,一是监控 fragment
的销毁,二是监控 ViewModel
的销毁,ViewModel
又分为 fragment
和 activity
的 ViewModel
。
先来看看 fragment
销毁的监控:
private val fragmentLifecycleCallbacks = object : FragmentManager.FragmentLifecycleCallbacks() {
override fun onFragmentCreated(
fm: FragmentManager,
fragment: Fragment,
savedInstanceState: Bundle?
) {
// 监控 ViewModel 的销毁
ViewModelClearedWatcher.install(fragment, deletableObjectReporter)
}
override fun onFragmentViewDestroyed(
fm: FragmentManager,
fragment: Fragment
) {
// 监控 Fragment 对应的 view 的销毁
val view = fragment.view
if (view != null) {
deletableObjectReporter.expectDeletionFor(
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
) {
// 监控 Fragment 的销毁
deletableObjectReporter.expectDeletionFor(
fragment, "${fragment::class.java.name} received Fragment#onDestroy() callback"
)
}
}
上面分为三块逻辑,分别是:执行监控 fragment
的 ViewModel
,监控 fragment
的 View
的销毁,监控 fragment
的销毁。
无论是 Activity
还是 Fragment
的 ViewModel
销毁监控,都在他们创建的时候调用了 ViewModelClearedWatcher.install()
方法,我们来看看它的实现:
fun install(
storeOwner: ViewModelStoreOwner,
deletableObjectReporter: DeletableObjectReporter
) {
val provider = ViewModelProvider(storeOwner, object : Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel?> create(modelClass: Class<T>): T =
ViewModelClearedWatcher(storeOwner, deletableObjectReporter) as T
})
provider.get(ViewModelClearedWatcher::class.java)
}
Activity
和 Fragment
他们都是 ViewModelStoreOwner
,上面的代码是创建了一个 ViewModel
,实现类是 ViewModelClearedWatcher
。
// ...
// We could call ViewModelStore#keys with a package spy in androidx.lifecycle instead,
// however that was added in 2.1.0 and we support AndroidX first stable release. viewmodel-2.0.0
// does not have ViewModelStore#keys. All versions currently have the mMap field.
private val viewModelMap: Map<String, ViewModel>? = try {
val storeClass = ViewModelStore::class.java
val mapField = try {
storeClass.getDeclaredField("map")
} catch (exception: NoSuchFieldException) {
// Field name changed from mMap to map with Kotlin conversion
// https://cs.android.com/androidx/platform/frameworks/support/+/8aa6ca1c924ab10d263b21b99b8790d5f0b50cc6
storeClass.getDeclaredField("mMap")
}
mapField.isAccessible = true
@Suppress("UNCHECKED_CAST")
mapField[storeOwner.viewModelStore] as Map<String, ViewModel>
} catch (ignored: Exception) {
SharkLog.d(ignored) { "Could not find ViewModelStore map of view models" }
null
}
override fun onCleared() {
viewModelMap?.values?.forEach { viewModel ->
deletableObjectReporter.expectDeletionFor(
viewModel, "${viewModel::class.java.name} received ViewModel#onCleared() callback"
)
}
}
// ...
当 ViewModel
被销毁的时候,ViewModelStoreOwner
会回调 ViewModel
的 onCleared()
方法,这里它通过反射的方式去到 ViewModelStore
去拿所有的 ViewModel
,对应的成员变量是 map
或者 mMap
。 然后通知 DeletableObjectReporter
对应的 ViewModelStoreOwner
的所有的 ViewModel
都已经被销毁。
最后
本篇文章介绍了 LeakCanary
的初始化,Activity
,Fragment
和 ViewModel
的销毁监控,后面的文章继续介绍后续内容。