2021-01-22 Leakcanary 源码流程(Activity 泄露监测)

这里是基于Leakcanary 2.6 来查看

1. 使用

2.6 后使用很简单,直接在app gradle 下增加依赖

dependencies {
    debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.6'
  }

这样就可以使用 Leakcanary,其原理为:注册一个ContentProvider 在ContentProvider 中 onCreate 方法中注册对应的检测程序。2.6 中这个ContentProvider 在这个包下面


570a64560ff98ced1f4a7626b84b6fa.png

2. 分析流程

进入AppWatcherInstaller中的onCreate方法

  override fun onCreate(): Boolean {
     //获取对应的Application
    val application = context!!.applicationContext as Application
    //初始化检测
    AppWatcher.manualInstall(application)
    return true
  }

继续往下走,到AppWatcher 中的 manualInstall 方法中

  @JvmOverloads
  fun manualInstall(
    application: Application,
    retainedDelayMillis: Long = TimeUnit.SECONDS.toMillis(5),
    watchersToInstall: List = appDefaultWatchers(application)
  ) {
     //检测线程
    checkMainThread()
    //判断是否初始化
    check(!isInstalled) {
      "AppWatcher already installed"
    }
    //检测retainedDelayMillis
    check(retainedDelayMillis >= 0) {
      "retainedDelayMillis $retainedDelayMillis must be at least 0 ms"
    }
    this.retainedDelayMillis = retainedDelayMillis
    //判断是否为Debuggable 构建,如果是,则开启日志
    if (application.isDebuggableBuild) {
      LogcatSharkLog.install()
    }
    // 初始化InternalLeakCanary
    LeakCanaryDelegate.loadLeakCanary(application)
    //注册监测程序
    watchersToInstall.forEach {
      it.install()
    }
  }

我们先来看InternalLeakCanary的初始化,点进去loadLeakCanary

  @Suppress("UNCHECKED_CAST")
  val loadLeakCanary by lazy {
    try {
      //这个我理解是通过反射的方式创建InternalLeakCanary对象,并调用invoke方法
      val leakCanaryListener = Class.forName("leakcanary.internal.InternalLeakCanary")
      leakCanaryListener.getDeclaredField("INSTANCE")
        .get(null) as (Application) -> Unit
    } catch (ignored: Throwable) {
      NoLeakCanary
    }
  }

走到InternalLeakCanary 的invoke方法中

  override fun invoke(application: Application) {
    //给_application 复制
    _application = application
    //判断是否为Debug构建,如果不是,会抛出异常
    checkRunningInDebuggableBuild()
     //为AppWatcher.objectWatcher增加监听
    AppWatcher.objectWatcher.addOnObjectRetainedListener(this)
    //创建AndroidHeapDumper
    val heapDumper = AndroidHeapDumper(application, createLeakDirectoryProvider(application))
    //GC触发器
    val gcTrigger = GcTrigger.Default

    val configProvider = { LeakCanary.config }
    //创建一个handler线程
    val handlerThread = HandlerThread(LEAK_CANARY_THREAD_NAME)
    handlerThread.start()
    //创建子线程handler
    val backgroundHandler = Handler(handlerThread.looper)
    //创建HeapDump 触发器
    heapDumpTrigger = HeapDumpTrigger(
      application, backgroundHandler, AppWatcher.objectWatcher, gcTrigger, heapDumper,
      configProvider
    )
    application.registerVisibilityListener { applicationVisible ->
      this.applicationVisible = applicationVisible
      heapDumpTrigger.onApplicationVisibilityChanged(applicationVisible)
    }
    registerResumedActivityListener(application)
    addDynamicShortcut(application)

    // We post so that the log happens after Application.onCreate()
    mainHandler.post {
      // https://github.com/square/leakcanary/issues/1981
      // We post to a background handler because HeapDumpControl.iCanHasHeap() checks a shared pref
      // which blocks until loaded and that creates a StrictMode violation.
      backgroundHandler.post {
        SharkLog.d {
          when (val iCanHasHeap = HeapDumpControl.iCanHasHeap()) {
            is Yup -> application.getString(R.string.leak_canary_heap_dump_enabled_text)
            is Nope -> application.getString(
              R.string.leak_canary_heap_dump_disabled_text, iCanHasHeap.reason()
            )
          }
        }
      }
    }
  }

上面主要还是创建一些对象,为之后使用做准备,接下来继续看监测器的install方法

  @JvmOverloads
  fun manualInstall(
    application: Application,
    retainedDelayMillis: Long = TimeUnit.SECONDS.toMillis(5),
    watchersToInstall: List = appDefaultWatchers(application)
  ) {
    //...
    //install 方法
    watchersToInstall.forEach {
      it.install()
    }
  }

其中watchersToInstall通过appDefaultWatchers(application)来获取

  fun appDefaultWatchers(
    application: Application,
    reachabilityWatcher: ReachabilityWatcher = objectWatcher
  ): List {
    return listOf(
      ActivityWatcher(application, reachabilityWatcher),
      FragmentAndViewModelWatcher(application, reachabilityWatcher),
      RootViewWatcher(reachabilityWatcher),
      ServiceWatcher(reachabilityWatcher)
    )
  }

返回一个列表,通过名称可以知道有监测Activity,Fragment、RootView、Service的,这里我们看监测Activity 的,也就是ActivityWatcher.install()方法

class ActivityWatcher(
  private val application: Application,
  private val reachabilityWatcher: ReachabilityWatcher
) : InstallableWatcher {

  private val lifecycleCallbacks =
    object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
      override fun onActivityDestroyed(activity: Activity) {
        //当Activity 调用onDestroyed 方法是,判断回收
        reachabilityWatcher.expectWeaklyReachable(
          activity, "${activity::class.java.name} received Activity#onDestroy() callback"
        )
      }
    }

  override fun install() {
     //通过Application 注册所有Activity 生命周期的监听
    application.registerActivityLifecycleCallbacks(lifecycleCallbacks)
  }

  override fun uninstall() {
    application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks)
  }
}

很明显,通过Application 注册所有Activity生命周期的监听,当Activity调用onDestroyed方法时,判断该Activity是否回收。其中reachabilityWatcher时在ActivityWatcher构造方法中传过来,往上回溯可以知道为ObjectWatcher对象,所以继续到ObjectWatcher.expectWeaklyReachable()方法中

  @Synchronized override fun expectWeaklyReachable(
    watchedObject: Any,
    description: String
  ) {
    //判断是否可用,默认返回true
    if (!isEnabled()) {
      return
    }
    //移除watchedObjects这个map中并且存在弱引用queue中的数据
    removeWeaklyReachableObjects()
    //通过uuid 随机生成key
    val key = UUID.randomUUID()
      .toString()
    //获取观察对象的时间
    val watchUptimeMillis = clock.uptimeMillis()
    //创建弱引用对象,注意最后一个参数把弱引用queue传过去了
    val reference =
      KeyedWeakReference(watchedObject, key, description, watchUptimeMillis, queue)
    //如果时debug模式,打印观察对象信息
    SharkLog.d {
      "Watching " +
        (if (watchedObject is Class<*>) watchedObject.toString() else "instance of ${watchedObject.javaClass.name}") +
        (if (description.isNotEmpty()) " ($description)" else "") +
        " with key $key"
    }
    //将弱引用对象保存到map中
    watchedObjects[key] = reference
    //执行检测
    checkRetainedExecutor.execute {
      moveToRetained(key)
    }
  }

上面代码主要是生成一个弱引用的对象,然后观察这个弱引用对象,继续看moveToRetained()方法

  @Synchronized private fun moveToRetained(key: String) {
    //又执行一遍一处,主要是一处watchedObjects这个map中并存在弱引用queue中的数据
    removeWeaklyReachableObjects()
    //通过key获取弱对象
    val retainedRef = watchedObjects[key]
    if (retainedRef != null) {
      //设置该对象的retainedUptimeMillis 
      retainedRef.retainedUptimeMillis = clock.uptimeMillis()
      //执行观察
      onObjectRetainedListeners.forEach { it.onObjectRetained() }
    }
  }

其中onObjectRetainedListeners中的listener是在InternalLeakCanary.invoke方法中添加的

override fun invoke(application: Application) {
      //...
     //为AppWatcher.objectWatcher增加监听
    AppWatcher.objectWatcher.addOnObjectRetainedListener(this)
   //...
  }

listener 是this 所以来到InternalLeakCanary.onObjectRetained()方法中

  override fun onObjectRetained() = scheduleRetainedObjectCheck()

  fun scheduleRetainedObjectCheck() {
    //判断是否初始化
    if (this::heapDumpTrigger.isInitialized) {
      //执行检查
      heapDumpTrigger.scheduleRetainedObjectCheck()
    }
  }

继续走到heapDumpTrigger.scheduleRetainedObjectCheck()方法中

  fun scheduleRetainedObjectCheck(
    delayMillis: Long = 0L
  ) {
    //checkScheduledAt 默认为0
    val checkCurrentlyScheduledAt = checkScheduledAt
    if (checkCurrentlyScheduledAt > 0) {
      return
    }
    //设置checkScheduledAt的值
    checkScheduledAt = SystemClock.uptimeMillis() + delayMillis
    //使用子线程handle 来执行,所以后面的方法是在子线程中执行
    backgroundHandler.postDelayed({
      checkScheduledAt = 0
      // 检查对象
      checkRetainedObjects()
    }, delayMillis)
  }

继续走,到checkRetainedObjects 方法中

  private fun checkRetainedObjects() {
    //做一些判断,我目前也不太理解这一个判断的用处
    val iCanHasHeap = HeapDumpControl.iCanHasHeap()

    val config = configProvider()
    //根据判断,是否返回,现在假设没有进入这个if中
    if (iCanHasHeap is Nope) {
      if (iCanHasHeap is NotifyingNope) {
        // Before notifying that we can't dump heap, let's check if we still have retained object.
        var retainedReferenceCount = objectWatcher.retainedObjectCount

        if (retainedReferenceCount > 0) {
          gcTrigger.runGc()
          retainedReferenceCount = objectWatcher.retainedObjectCount
        }

        val nopeReason = iCanHasHeap.reason()
        val wouldDump = !checkRetainedCount(
          retainedReferenceCount, config.retainedVisibleThreshold, nopeReason
        )

        if (wouldDump) {
          val uppercaseReason = nopeReason[0].toUpperCase() + nopeReason.substring(1)
          onRetainInstanceListener.onEvent(DumpingDisabled(uppercaseReason))
          showRetainedCountNotification(
            objectCount = retainedReferenceCount,
            contentText = uppercaseReason
          )
        }
      } else {
        SharkLog.d {
          application.getString(
            R.string.leak_canary_heap_dump_disabled_text, iCanHasHeap.reason()
          )
        }
      }
      return
    }
    //获取没有被回收对象的个数
    var retainedReferenceCount = objectWatcher.retainedObjectCount
    //如果没有被回收的对象个数大于0
    if (retainedReferenceCount > 0) {
      //执行一遍GC
      gcTrigger.runGc()
      //从新获取没有被回收对象的个数
      retainedReferenceCount = objectWatcher.retainedObjectCount
    }
    //检查没有被回收对象的个数,如果少于5个,不会往下执行
    if (checkRetainedCount(retainedReferenceCount, config.retainedVisibleThreshold)) return
    //获取当前时间
    val now = SystemClock.uptimeMillis()
    //获取当前时间和上次执行时间的间隔
    val elapsedSinceLastDumpMillis = now - lastHeapDumpUptimeMillis
    //如果小于60_000L,这个应该是60秒...
    if (elapsedSinceLastDumpMillis < WAIT_BETWEEN_HEAP_DUMPS_MILLIS) {
      onRetainInstanceListener.onEvent(DumpHappenedRecently)
      //发送通知
      showRetainedCountNotification(
        objectCount = retainedReferenceCount,
        contentText = application.getString(R.string.leak_canary_notification_retained_dump_wait)
      )
      //延迟执行后面操作,也就是用60_000L - 当前间隔
      scheduleRetainedObjectCheck(
        delayMillis = WAIT_BETWEEN_HEAP_DUMPS_MILLIS - elapsedSinceLastDumpMillis
      )
      return
    }

    dismissRetainedCountNotification()
    val visibility = if (applicationVisible) "visible" else "not visible"
    //获取内存.hprof文件
    dumpHeap(
      retainedReferenceCount = retainedReferenceCount,
      retry = true,
      reason = "$retainedReferenceCount retained objects, app is $visibility"
    )
  }

到这里,就清楚Activity对象监测的流程:创建一个Activity 的弱引用对象,保存到map中,当Activity对象回收时,会将Activity的弱引用对象保存到弱引用的queue中,循环queue获取弱引用对象,移除map中的Activity 的弱引用对象, GC后还存在map中的Activity弱引用对象就是发生泄漏的对象。当这个对象超过5个,就会获取内存.hprof文件,检查对应的引用链。

你可能感兴趣的:(2021-01-22 Leakcanary 源码流程(Activity 泄露监测))