本文仅对核心进行浅析,因此不说明堆栈数据解析与展示的相关功能。

LeakCanary 提供了一个在开发阶段方便地寻找内存泄漏问题的方式,通过它可以快速定位发生内存泄漏的组件,并获得其完整的引用链。

虽然 LeakCanary 的功能非常强大,但其核心功能的源码却意料之外简洁易懂。

金丝雀(Canary)是一种对一氧化碳极为敏感的鸟类,17 世纪开始,英国的矿工们就将金丝雀带入矿井中,一旦金丝雀发生异样,则矿工们可提前感知危险到来,以迅速撤出矿井。

因此金丝雀具有报警器的含义。而在现在的软件开发中,该词也通常用于表示最新的测试版本。

原理

LeakCanary 通过监听各个具备生命周期组件的生命周期状态,并通过弱引用记录生命周期已进入销毁阶段的组件,当保留对象超过阈值时,LeakCanary 将记录虚拟机堆栈信息,并对其进行分析,之后向开发者展示。

源码解析

初始化

无需手动初始化的魔法来自 Content Provider。

/**
 * Content providers are loaded before the application class is created. [AppWatcherInstaller] is
 * used to install [leakcanary.AppWatcher] on application start.
 */
internal sealed class AppWatcherInstaller : ContentProvider() {

  /**
   * [MainProcess] automatically sets up the LeakCanary code that runs in the main app process.
   */
  internal class MainProcess : AppWatcherInstaller()

  /**
   * When using the `leakcanary-android-process` artifact instead of `leakcanary-android`,
   * [LeakCanaryProcess] automatically sets up the LeakCanary code
   */
  internal class LeakCanaryProcess : AppWatcherInstaller()

  override fun onCreate(): Boolean {
    val application = context!!.applicationContext as Application
    AppWatcher.manualInstall(application)
    return true
  }

  ...
}

onCreate() 中调用了 AppWatcher.manualInstall(),实际内部是对非公开方法 InternalAppWatcher.install() 的一个包装。

/**
 * [AppWatcher] is automatically installed in the main process on startup. You can
 * disable this behavior by overriding the `leak_canary_watcher_auto_install` boolean resource:
 *
 * ```
 * <?xml version="1.0" encoding="utf-8"?>
 * <resources>
 *   <bool name="leak_canary_watcher_auto_install">false</bool>
 * </resources>
 * ```
 *
 * If you disabled automatic install then you can call this method to install [AppWatcher].
 */
fun manualInstall(application: Application) {
  InternalAppWatcher.install(application)
}

InternalAppWatcher.install() 实现如下。

fun install(application: Application) {
  checkMainThread()
  if (this::application.isInitialized) {
    return
  }
  InternalAppWatcher.application = application
  if (isDebuggableBuild) {
    SharkLog.logger = DefaultCanaryLog()
  }

  val configProvider = { AppWatcher.config }
  ActivityDestroyWatcher.install(application, objectWatcher, configProvider)
  FragmentDestroyWatcher.install(application, objectWatcher, configProvider)
  onAppWatcherInstalled(application)
}

在将 application 作为成员变量保存后,通过 ActivityDestroyWatcher.install()FragmentDestroyWatcher.install() 对 Activity 与 Fragment 的内存泄漏问题进行监控,最后调用由外部设置的 Lambda 回调 onAppWatcherInstalled

Activity 监控

进入 ActivityDestroyWatcher.install()

internal class ActivityDestroyWatcher private constructor(
  private val objectWatcher: ObjectWatcher,
  private val configProvider: () -> Config
) {

  private val lifecycleCallbacks =
    object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
      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.registerActivityLifecycleCallbacks(activityDestroyWatcher.lifecycleCallbacks)
    }
  }
}

install()application 中注册了一个监听 Activity 销毁的生命周期监听器,当 activity 销毁时将其添加到 objectWatcher 中。

noOpDelegate() 是一个带实化泛型的内联函数,作用是通过动态代理创建一个空实现接口的实例。

/**
 * Watches the provided [watchedObject].
 *
 * @param description Describes why the object is watched.
 */
@Synchronized fun watch(
  watchedObject: Any,
  description: String
) {
  if (!isEnabled()) {
    return
  }
  removeWeaklyReachableObjects()
  val key = UUID.randomUUID()
      .toString()
  val watchUptimeMillis = clock.uptimeMillis()
  val reference =
    KeyedWeakReference(watchedObject, key, description, watchUptimeMillis, queue)
  
  ...

  watchedObjects[key] = reference
  checkRetainedExecutor.execute {
    moveToRetained(key)
  }
}

ObjectWatcher.watch() 将传入的对象通过自定义弱引用类型 KeyedWeakReference 保存到成员函数映射 watchedObjects 中,并通过引用队列成员函数 queue 检查对象是否被释放。不过在此前后,watch() 都进行了一些操作。

添加对象前,watch() 调用了 removeWeaklyReachableObjects() 移除了 watchedObjects 中所有已添加到 queue 中的弱引用(即已经被回收对象的弱引用)。

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.
  var ref: KeyedWeakReference?
  do {
    ref = queue.poll() as KeyedWeakReference?
    if (ref != null) {
      watchedObjects.remove(ref.key)
    }
  } while (ref != null)
}

添加对象后,watch() 通过向 checkRetainedExecutor 推送一个执行 moveToRetained()Runnable,当在 watchedObjects 中发现其弱引用后记录记录时间,并调用回调。

checkRetainedExecutor 默认实现是由 InternalAppWatcher 构建的主线程 Executor,内部调用了 mainHandler.postDelayed() 在延迟 AppWatcher.config.watchDurationMillis 后执行 Runnable

@Synchronized private fun moveToRetained(key: String) {
  removeWeaklyReachableObjects()
  val retainedRef = watchedObjects[key]
  if (retainedRef != null) {
    retainedRef.retainedUptimeMillis = clock.uptimeMillis()
    onObjectRetainedListeners.forEach { it.onObjectRetained() }
  }
}

最终由核心外部注册的 OnObjectRetainedListener 将会被调用,进行堆栈分析。

Fragment 监控

FragmentDestroyWatcher.install() 的逻辑相比 ActivityDestroyWatcher.install() 较为复杂,但原理相同。

fun install(
  application: Application,
  objectWatcher: ObjectWatcher,
  configProvider: () -> AppWatcher.Config
) {
  val fragmentDestroyWatchers = mutableListOf<(Activity) -> Unit>()

  if (SDK_INT >= O) {
    fragmentDestroyWatchers.add(
        AndroidOFragmentDestroyWatcher(objectWatcher, configProvider)
    )
  }

  getWatcherIfAvailable(
      ANDROIDX_FRAGMENT_CLASS_NAME,
      ANDROIDX_FRAGMENT_DESTROY_WATCHER_CLASS_NAME,
      objectWatcher,
      configProvider
  )?.let {
    fragmentDestroyWatchers.add(it)
  }

  getWatcherIfAvailable(
      ANDROID_SUPPORT_FRAGMENT_CLASS_NAME,
      ANDROID_SUPPORT_FRAGMENT_DESTROY_WATCHER_CLASS_NAME,
      objectWatcher,
      configProvider
  )?.let {
    fragmentDestroyWatchers.add(it)
  }

  if (fragmentDestroyWatchers.size == 0) {
    return
  }

  application.registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
    override fun onActivityCreated(
      activity: Activity,
      savedInstanceState: Bundle?
    ) {
      for (watcher in fragmentDestroyWatchers) {
        watcher(activity)
      }
    }
  })
}

通过对 Android 8.0AndroidXAndroid Support Library 三种情况进行分析并创建监听器后,监听器最终在对 Activity 创建的生命周期监听中设置到 Activity 中。

在三种类型的监听器中,以 AndroidX 对应的监听器 AndroidXFragmentDestroyWatcher 为例,通过生命周期监听的方式监听 Fragment 与内部 View 实现销毁对象观测功能的实现与 ActivityDestroyWatcher 基本一致。

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)
    }
  }
}

至此完成核心源码的分析过程。