LeakCanary 源码阅读笔记(一)

324 阅读3分钟

LeakCanary 源码阅读笔记(一)

20241102-5.jpg

LeakCanary 可以探测 Android 应用程序在运行时是否发生了内存泄漏,只能够用在 Debug 的应用上,他和 OkHttp 一样都是出之 Square 公司之手。学习 LeakCanary 的源码对理解 Android 的泄漏和内存 Dump 有非常大的帮助,要学习写代码,就学一流的代码,不说废话了,开始 LeakCanary 的源码学习。

LeakCanary 初始化

LeakCanary 不需要手动写代码初始化,只需要在 gradle 中添加依赖就好了,然后 App 在启动时就会自动运行,年轻的时候我也非常好奇是怎么实现的,其实就是通过 ContentProvider 实现的,它可能是存在感最低的四大组建,但是 ContentProvider 他有一个特点,在 App 初始化的过程中也会初始化 ContentProvider,这部分代码我就不细说了,感兴趣的同学可去网上找找相关的资料。
LeakCanary 对应的初始化的 ContentProviderMainProcessAppWatcherInstaller , 对应的 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;另外一个是各种 WatcherWatcher 就是用来监控各种已经进入 destroy 生命周期的 Android 组件;当 Watcher 发现组建已经 destory 了,但是它所对应的 Java 实例并没有被销毁就表示当前已经出现了泄漏,Watcher 就会通知 LeakCanaryDelegatedump 内存,并分析内存,找到泄漏对象的 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:监控 FragmentViewModel 的销毁
  • 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 的监控分为三种,系统的 fragmentandroidxfragmentsupportfragment,我们只分析 androidxfragment 就好,其他两种大家自行分析。

androidxfragment 的监控类是 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 又分为 fragmentactivityViewModel

先来看看 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"
    )
  }
}

上面分为三块逻辑,分别是:执行监控 fragmentViewModel,监控 fragmentView 的销毁,监控 fragment 的销毁。

无论是 Activity 还是 FragmentViewModel 销毁监控,都在他们创建的时候调用了 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)
}

ActivityFragment 他们都是 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 会回调 ViewModelonCleared() 方法,这里它通过反射的方式去到 ViewModelStore 去拿所有的 ViewModel,对应的成员变量是 map 或者 mMap。 然后通知 DeletableObjectReporter 对应的 ViewModelStoreOwner 的所有的 ViewModel 都已经被销毁。

最后

本篇文章介绍了 LeakCanary 的初始化,ActivityFragmentViewModel 的销毁监控,后面的文章继续介绍后续内容。