LeakCanary2.7源码分析

简介

本篇LeakCanary的源码分析,基于2.7版本

  • 从2.x版本全部使用Kotlin进行编码
  • 可以在一次分析中检测到多个内存泄漏

    当应用进入后台,或者在前台泄漏到达5次时,将heap数据进行存储

  • 对内存泄漏进行分组
    1. 按照泄漏相似原因在UI中分组
    2. 使用多屏样式,针对多组和单组列表样式进行查看
    3. 对泄漏原因及trace日志进行高光展示
    4. 泄漏能够分享到StackOverFlow
  • 引入了新库LeakSentry

1.可以用来检测何时发生内存泄漏并触发LeakCanary
2.可以在生产环境中单独使用

  • 内存泄漏分析库由haha替换为了shark

1.内存占用减少了90%,速度提升了6倍
2.与应用程序在同一进程中,使用低优先级线程进行工作
3.不再依赖 Perflib 和 TroveJ。对 Okio 的新依赖

  • 侵入性降低,只需依赖即可使用
  • 提供了更简单的配置选项
  • 从Support库迁移到Android X
1、LeakCanary的启动及初始化
  1. 新版本的LeakCanary只需要添加依赖导入即可使用,不需要手动调用install()来实现注册。
  2. 原理在于其利用了ContentProvider的onCreate()方法先于Applicaiton的onCreate()方法执行。
源码查看
1.1 leakcanary-object-watcher-android AndroidManifest.xml中定义contentProvider
  <application>
        <provider
            android:name="leakcanary.internal.AppWatcherInstaller$MainProcess"
            android:authorities="${applicationId}.leakcanary-installer"
            android:enabled="@bool/leak_canary_watcher_auto_install"
            android:exported="false" />
    </application>
1.2 AppWatcherInstaller.kt 中onCreate()
internal sealed class AppWatcherInstaller : ContentProvider() {
   .... 省略非关键代码
  override fun onCreate(): Boolean {
    val application = context!!.applicationContext as Application
    // 加载LeakCanary
    AppWatcher.manualInstall(application)
    return true
  }

我们看到在AppWatcherInstaller的onCreate()方法中,首先获取了Application然后手动调用AppWatcher.manualInstall(application)来加载LeakCanary

  • AppWatcher.manualInstall(application)
  @JvmOverloads
  fun manualInstall(
    application: Application,
    // 默认保持5s延迟检测
    retainedDelayMillis: Long = TimeUnit.SECONDS.toMillis(5),
    // watchers 列表默认为appDefaultWatchers
    watchersToInstall: List<InstallableWatcher> = appDefaultWatchers(application)
  ) {
  // 主线程判断
    checkMainThread()
    // 防止重复加载
    if (isInstalled) {
      throw IllegalStateException(
        "AppWatcher already installed, see exception cause for prior install call", installCause
      )
    }
    // 延时时间检测,必须大于0才可以,否则抛出异常
    check(retainedDelayMillis >= 0) {
      "retainedDelayMillis $retainedDelayMillis must be at least 0 ms"
    }
    installCause = RuntimeException("manualInstall() first called here")
    // 缓存延迟检测时间
    this.retainedDelayMillis = retainedDelayMillis
    // LogcatSharkLog只有在debug状态下才会打印
    if (application.isDebuggableBuild) {
      LogcatSharkLog.install()
    }
    // Requires AppWatcher.objectWatcher to be set
    // 获取InternalLeakCanary实例加载leakCanary
    LeakCanaryDelegate.loadLeakCanary(application)
    // 循环加载watcher
    watchersToInstall.forEach {
      it.install()
    }
  }
  • appDefaultWatchers
 fun appDefaultWatchers(
    application: Application,
    // 默认为objectWatcher
    reachabilityWatcher: ReachabilityWatcher = objectWatcher
  ): List<InstallableWatcher> {
    return listOf(
      ActivityWatcher(application, reachabilityWatcher),
      FragmentAndViewModelWatcher(application, reachabilityWatcher),
      RootViewWatcher(reachabilityWatcher),
      ServiceWatcher(reachabilityWatcher)
    )

reachabilityWatcher默认值为objectWatcher

默认watchers:

1.ActivityWatcher
2.FragmentAndViewModelWatcher
3.RootViewWatcher
4.ServiceWatcher

在manualInstall方法中做了以下几件事情:

  1. 设置默认5s的延迟检测时间
  2. 设置默认安装的内存监视器安装list
  3. 非主线程运行判断拦截
  4. leakCanary重复加载判断拦截
  5. 延迟检测时间检测,不能小于0s
  6. 缓存延迟检测时间
  7. 判断是否是debug状态选择性安装LogcatSharkLog
  8. 获取InternalLeakCanary实例并加载leakCanary
  9. 循环加载watchers列表中内存监视器
2、内存泄漏检测怎么实现的
2.1 ActivityWatcher
class ActivityWatcher(
  private val application: Application,
  private val reachabilityWatcher: ReachabilityWatcher
) : InstallableWatcher {

  private val lifecycleCallbacks =
    object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
      override fun onActivityDestroyed(activity: Activity) {
        // 通过objectWatcher监视activity
        reachabilityWatcher.expectWeaklyReachable(
          activity, "${activity::class.java.name} received Activity#onDestroy() callback"
        )
      }
    }

  override fun install() {
  // 注册应用activity生命周期回调
    application.registerActivityLifecycleCallbacks(lifecycleCallbacks)
  }

  override fun uninstall() {
  // 反注册activity生命周期回调
    application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks)
  }
}

通过install方法注册了activity的生命周期回调,并在onActivityDestroyed()方法中通过ObjectWatcher对activity进行监视

  • ObjectWatcher.kt 中 expectWeaklyReachable方法
  @Synchronized override fun expectWeaklyReachable(
    watchedObject: Any,
    description: String
  ) {
    if (!isEnabled()) {
      return
    }
    // 2.1.1 移除弱引用可达Activity对象
    removeWeaklyReachableObjects()
    val key = UUID.randomUUID()
      .toString()
    val watchUptimeMillis = clock.uptimeMillis()
    // 2.1.2 根据activity键创建弱引用,并绑定到引用队列中
    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"
    }
    // 将引用以键值形式存储在被监视的对象map集合中
    watchedObjects[key] = reference
    // 通过线程池来启动任务
    checkRetainedExecutor.execute {
    // 2.1.3 获取不能回收的activity
      moveToRetained(key)
    }
  }
  • 2.1.1 ObjectWatcher.kt 中 removeWeaklyReachableObjects
 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.
    // 在GC和finalization之前,弱应用对象会变为weakly reachable
    var ref: KeyedWeakReference?
    // 移除处于弱引用状态下的对象,留下不能被GC回收的对象
    do {
      ref = queue.poll() as KeyedWeakReference?
      if (ref != null) {
        watchedObjects.remove(ref.key)
      }
    } while (ref != null)
  }
  • 2.1.2 ObjectWatcher.kt 中 KeyedWeakReference(watchedObject, key, description, watchUptimeMillis, queue)
// 通过传入的参数构建WeakReference
class KeyedWeakReference(
  referent: Any,
  val key: String,
  val description: String,
  val watchUptimeMillis: Long,
  referenceQueue: ReferenceQueue<Any>
) : WeakReference<Any>(
  referent, referenceQueue
)
  • 2.1.3 ObjectWatcher.kt 中 moveToRetained(key)
  @Synchronized private fun moveToRetained(key: String) {
  // 移除不发生内存泄漏activity
    removeWeaklyReachableObjects()
    val retainedRef = watchedObjects[key]
    if (retainedRef != null) {
        // 保存泄漏对象时间戳
      retainedRef.retainedUptimeMillis = clock.uptimeMillis()
      // 通知InternalLeakCanary发生内存泄漏
      onObjectRetainedListeners.forEach { 
      // 2.1.4 
      it.onObjectRetained() 
      }
    }
  }
  • 2.1.4 InternalLeakCanary.kt 中onObjectRetained
 override fun onObjectRetained() = scheduleRetainedObjectCheck()

  fun scheduleRetainedObjectCheck() {
    if (this::heapDumpTrigger.isInitialized) {
       // 2.1.5 通知heapDumpTrigger定时检查持有对象
      heapDumpTrigger.scheduleRetainedObjectCheck()
    }
  }
  • 2.1.5 HeapDumpTrigger.kt 中scheduleRetainedObjectCheck
  fun scheduleRetainedObjectCheck(
    delayMillis: Long = 0L
  ) {
    val checkCurrentlyScheduledAt = checkScheduledAt
    if (checkCurrentlyScheduledAt > 0) {
      return
    }
    checkScheduledAt = SystemClock.uptimeMillis() + delayMillis
    // 通过handler发送延迟检测对象任务
    backgroundHandler.postDelayed({
      checkScheduledAt = 0
     // 2.1.6 检测持有对象
      checkRetainedObjects()
    }, delayMillis)
  }
  • 2.1.6 HeapDumpTrigger.kt 中 checkRetainedObjects()
private fun checkRetainedObjects() {
    // 堆存储判断 
    val iCanHasHeap = HeapDumpControl.iCanHasHeap()
    // 获取provider配置
    val config = configProvider()

    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) {
         // 2.1.7 手动调用GC
          gcTrigger.runGc()
          // 对持有对象数进行赋值
          retainedReferenceCount = objectWatcher.retainedObjectCount
        }
        
        val nopeReason = iCanHasHeap.reason()
        // 2.1.8 检测是否需要进行堆存储trace
        val wouldDump = !checkRetainedCount(
          retainedReferenceCount, config.retainedVisibleThreshold, nopeReason
        )
        
        if (wouldDump) {
          val uppercaseReason = nopeReason[0].toUpperCase() + nopeReason.substring(1)
          // 进行持有实例对象回调
          onRetainInstanceListener.onEvent(DumpingDisabled(uppercaseReason))
          // 2.1.9 显示持有对象通知
          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

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

    if (checkRetainedCount(retainedReferenceCount, config.retainedVisibleThreshold)) return

    val now = SystemClock.uptimeMillis()
    val elapsedSinceLastDumpMillis = now - lastHeapDumpUptimeMillis
    if (elapsedSinceLastDumpMillis < WAIT_BETWEEN_HEAP_DUMPS_MILLIS) {
      onRetainInstanceListener.onEvent(DumpHappenedRecently)
      showRetainedCountNotification(
        objectCount = retainedReferenceCount,
        contentText = application.getString(R.string.leak_canary_notification_retained_dump_wait)
      )
       // 定时检测持有对象
      scheduleRetainedObjectCheck(
        delayMillis = WAIT_BETWEEN_HEAP_DUMPS_MILLIS - elapsedSinceLastDumpMillis
      )
      return
    }
    // 2.1.10 关闭持有对象数量通知
    dismissRetainedCountNotification()
    val visibility = if (applicationVisible) "visible" else "not visible"
    // 2.1.11 堆转储
    dumpHeap(
      retainedReferenceCount = retainedReferenceCount,
      retry = true,
      reason = "$retainedReferenceCount retained objects, app is $visibility"
    )
  }
  • 2.1.7 GcTrigger.kt 中runGc()
interface GcTrigger {
  object Default : GcTrigger {
    override fun runGc() {
    // 调用Runtime系统的gc方法
      Runtime.getRuntime()
        .gc(
        // 延迟100ms
      enqueueReferences()
      System.runFinalization()
    }

    private fun enqueueReferences() {
      try {
        Thread.sleep(100)
      } catch (e: InterruptedException) {
        throw AssertionError()
      }
    }
  }
}
  • 2.1.8 HeapDumpTrigger.kt 中checkRetainedCount
 private fun checkRetainedCount(
    retainedKeysCount: Int,
    retainedVisibleThreshold: Int,
    nopeReason: String? = null
  ): Boolean {
    // 检测持有的对象数量是否发生了变更
    val countChanged = lastDisplayedRetainedObjectCount != retainedKeysCount
    lastDisplayedRetainedObjectCount = retainedKeysCount
    // 没有内存泄露的对象
    if (retainedKeysCount == 0) {
      if (countChanged) {
        SharkLog.d { "All retained objects have been garbage collected" }
        onRetainInstanceListener.onEvent(NoMoreObjects)
        // 显示没有持有对象通知
        showNoMoreRetainedObjectNotification()
      }
      return true
    }
   ... 省略非关键代码
   
   // 持有的对象数小于阀值时(默认阀值为5)
    if (retainedKeysCount < retainedVisibleThreshold) {
      if (applicationVisible || applicationInvisibleLessThanWatchPeriod) {
        if (countChanged) {
          onRetainInstanceListener.onEvent(BelowThreshold(retainedKeysCount))
        }
        // 显示持有对象通知
        showRetainedCountNotification(
          objectCount = retainedKeysCount,
          contentText = application.getString(
            R.string.leak_canary_notification_retained_visible, retainedVisibleThreshold
          )
        )
        // 延迟2s定时检测持有的对象
        scheduleRetainedObjectCheck(
          delayMillis = WAIT_FOR_OBJECT_THRESHOLD_MILLIS
        )
        return true
      }
    }
    return false
  }
  1. 检查对象持有数量是否发生变更
  2. 无持有对象时显示没有持有对象通知
  3. 持有对象数小于默认阀值时,发送持有对象通知,并定时间隔2s检测持有对象数量
  • 2.1.9 HeapDumpTrigger.kt 中showRetainedCountNotification
private fun showRetainedCountNotification(
    objectCount: Int,
    contentText: String
  ) {
   // 移除dismiss通知回调 backgroundHandler.removeCallbacks(scheduleDismissRetainedCountNotification)
    if (!Notifications.canShowNotification) {
      return
    }
    // 通过调用系统通知方法发送通知
    @Suppress("DEPRECATION")
    val builder = Notification.Builder(application)
      .setContentTitle(
        application.getString(R.string.leak_canary_notification_retained_title, objectCount)
      )
      .setContentText(contentText)
      .setAutoCancel(true)
      .setContentIntent(NotificationReceiver.pendingIntent(application, DUMP_HEAP))
    val notification =
      Notifications.buildNotification(application, builder, LEAKCANARY_LOW)
    notificationManager.notify(R.id.leak_canary_notification_retained_objects, notification)
  }
  • 2.1.10 HeapDumpTrigger.kt 中dismissRetainedCountNotification()
 private fun dismissRetainedCountNotification() {
   // 移除handler回调 backgroundHandler.removeCallbacks(scheduleDismissRetainedCountNotification)
   // 调用系统通知取消方法
   notificationManager.cancel(R.id.leak_canary_notification_retained_objects)
  }
  • 2.1.11 HeapDumpTrigger.kt 中dumpHeap
  private fun dumpHeap(
    retainedReferenceCount: Int,
    retry: Boolean,
    reason: String
  ) {
    saveResourceIdNamesToMemory()
    val heapDumpUptimeMillis = SystemClock.uptimeMillis()
    KeyedWeakReference.heapDumpUptimeMillis = heapDumpUptimeMillis
    // 2.1.12 查看堆转储结果
    when (val heapDumpResult = heapDumper.dumpHeap()) {
        // 无堆转储
      is NoHeapDump -> {
        if (retry) {
          SharkLog.d { "Failed to dump heap, will retry in $WAIT_AFTER_DUMP_FAILED_MILLIS ms" }
          scheduleRetainedObjectCheck(
            delayMillis = WAIT_AFTER_DUMP_FAILED_MILLIS
          )
        } else {
          SharkLog.d { "Failed to dump heap, will not automatically retry" }
        }
        // 显示堆持有的通知数
        showRetainedCountNotification(
          objectCount = retainedReferenceCount,
          contentText = application.getString(
            R.string.leak_canary_notification_retained_dump_failed
          )
        )
      }
      // 存在堆转储文件
      is HeapDump -> {
        lastDisplayedRetainedObjectCount = 0
        lastHeapDumpUptimeMillis = SystemClock.uptimeMillis()
        objectWatcher.clearObjectsWatchedBefore(heapDumpUptimeMillis)
        // 通过开启服务来分析堆转储文件
        HeapAnalyzerService.runAnalysis(
          context = application,
          heapDumpFile = heapDumpResult.file,
          heapDumpDurationMillis = heapDumpResult.durationMillis,
          heapDumpReason = reason
        )
      }
    }
  }

通过heapDumper来进行堆转储文件进行检查,如果不存在显示通知,如果存在开启服务对存在的文件进行分析

  • 2.1.12 HeapDumper.kt 中dumpHeap()
internal interface HeapDumper {

  /**
   * @return a [File] referencing the dumped heap, or [.RETRY_LATER] if the heap could
   * not be dumped.
   */
  fun dumpHeap(): DumpHeapResult
}

我们看到HeapDumper是一个接口,那直接查看其实现类来看下具体实现

  • 2.1.13 AndroidHeapDumper.kt 中dumpHeap()
internal class AndroidHeapDumper(
  context: Context,
  private val leakDirectoryProvider: LeakDirectoryProvider
) : HeapDumper {

  private val context: Context = context.applicationContext

  override fun dumpHeap(): DumpHeapResult {
  // 2.1.14 查询heap文件是否为空,如果为不为空直接使用之前的文件进行存储,否则返回NoHeapDump状态
    val heapDumpFile = leakDirectoryProvider.newHeapDumpFile() ?: return NoHeapDump
    
    val waitingForToast = FutureResult<Toast?>()
    showToast(waitingForToast)
    // 等待5s显示toast
    if (!waitingForToast.wait(5, SECONDS)) {
      SharkLog.d { "Did not dump heap, too much time waiting for Toast." }
      return NoHeapDump
    }
    // 显示通知
    val notificationManager =
      context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    if (Notifications.canShowNotification) {
      val dumpingHeap = context.getString(R.string.leak_canary_notification_dumping)
      val builder = Notification.Builder(context)
        .setContentTitle(dumpingHeap)
      val notification = Notifications.buildNotification(context, builder, LEAKCANARY_LOW)
      notificationManager.notify(R.id.leak_canary_notification_dumping_heap, notification)
    }

    val toast = waitingForToast.get()

    return try {
      val durationMillis = measureDurationMillis {
      // 2.1.15 生成heap文件
        Debug.dumpHprofData(heapDumpFile.absolutePath)
      }
      if (heapDumpFile.length() == 0L) {
        SharkLog.d { "Dumped heap file is 0 byte length" }
        NoHeapDump
      } else {
        HeapDump(file = heapDumpFile, durationMillis = durationMillis)
      }
    } catch (e: Exception) {
      SharkLog.d(e) { "Could not dump heap" }
      // Abort heap dump
      NoHeapDump
    } finally {
      cancelToast(toast)
      notificationManager.cancel(R.id.leak_canary_notification_dumping_heap)
    }
  }
  • 2.1.14 LeakDirectoryProvider 中newHeapDumpFile方法
  fun newHeapDumpFile(): File? {
    cleanupOldHeapDumps()
    
    var storageDirectory = externalStorageDirectory()
    // 如果文件夹不满足存储条件
    if (!directoryWritableAfterMkdirs(storageDirectory)) {
       // 无权限检查写权限
      if (!hasStoragePermission()) {
        if (requestExternalStoragePermission()) {
          SharkLog.d { "WRITE_EXTERNAL_STORAGE permission not granted, requesting" }
          requestWritePermissionNotification()
        } else {
          SharkLog.d { "WRITE_EXTERNAL_STORAGE permission not granted, ignoring" }
        }
      } else {
        val state = Environment.getExternalStorageState()
        // 无存储卡 打印日志
        if (Environment.MEDIA_MOUNTED != state) {
          SharkLog.d { "External storage not mounted, state: $state" }
        } else {
          SharkLog.d {
            "Could not create heap dump directory in external storage: [${storageDirectory.absolutePath}]"
          }
        }
      }
      // Fallback to app storage.
      storageDirectory = appStorageDirectory()
        // 返回null
      if (!directoryWritableAfterMkdirs(storageDirectory)) {
        SharkLog.d {
          "Could not create heap dump directory in app storage: [${storageDirectory.absolutePath}]"
        }
        return null
      }
    }
    // 直接heap返回文件
    val fileName = SimpleDateFormat("yyyy-MM-dd_HH-mm-ss_SSS'.hprof'", Locale.US).format(Date())
    return File(storageDirectory, fileName)
  }
  • 2.1.15 Debug.java 中Debug.dumpHprofData
    // 调用系统sdk提供的方法生成heap文件
    public static void dumpHprofData(String fileName) throws IOException {
        SDk.dumpHprofData(fileName);
    }
2.2 FragmentAndViewModelWatcher
  • 2.2.1 FragmentAndViewModelWatcher.kt 中install方法
  override fun install() {
    application.registerActivityLifecycleCallbacks(lifecycleCallbacks)
  }

在install方法中注册Activity生命周期回调,因为Fragment是依附于Activity来添加,所以此处注册Activity生命周期回调

  • 2.2.2 FragmentAndViewModelWatcher.kt 中lifecycleCallbacks回调
  private val lifecycleCallbacks =
    object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
        // 注册onActivityCreate生命周期回调
      override fun onActivityCreated(
        activity: Activity,
        savedInstanceState: Bundle?
      ) {
        // 2.2.3 遍历fragmentDestroyWatchers
        for (watcher in fragmentDestroyWatchers) {
            // watcher监测activity
          watcher(activity)
        }
      }
    }
  • watch(activity) 实际是对应kotlin中Functions.kt文件的Function1接口,P1为Activity,R为Unit即为Java的void
package kotlin.jvm.functions

interface Function1<in P1, out R> : kotlin.Function<R> {
    fun invoke(p1: P1): R
}

也就是说,watch(activity)最终调用的是watcher中的invoke(Activity)方法

  • 2.2.3 FragmentAndViewModelWatcher.kt 中fragmentDestroyWatchers
  private val fragmentDestroyWatchers: List<(Activity) -> Unit> = run {
    val fragmentDestroyWatchers = mutableListOf<(Activity) -> Unit>()
    
    // SDK版本大于Android O(26 Android8.0)
    if (SDK_INT >= O) {
      fragmentDestroyWatchers.add(
      // 添加Android O fragmentDestoryWatcher
      // Android O 版本DestoryWatcher
        AndroidOFragmentDestroyWatcher(reachabilityWatcher)
      )
    }
    
    // 2.2.4 针对androidX 版本fragment
    getWatcherIfAvailable(
      ANDROIDX_FRAGMENT_CLASS_NAME,
      ANDROIDX_FRAGMENT_DESTROY_WATCHER_CLASS_NAME,
      reachabilityWatcher
    )?.let {
    // 2.4.5 添加观察者
      fragmentDestroyWatchers.add(it)
    }
    
    // 针对support 版本fragment
    getWatcherIfAvailable(
      ANDROID_SUPPORT_FRAGMENT_CLASS_NAME,
      ANDROID_SUPPORT_FRAGMENT_DESTROY_WATCHER_CLASS_NAME,
      reachabilityWatcher
    )?.let {
        // 添加观察者
      fragmentDestroyWatchers.add(it)
    }
    // 返回watcher集合
    fragmentDestroyWatchers
  }
  • 2.2.4 FragmentAndViewModelWatcher.kt 中getWatcherIfAvailable
  private fun getWatcherIfAvailable(
    fragmentClassName: String,
    watcherClassName: String,
    reachabilityWatcher: ReachabilityWatcher
  ): ((Activity) -> Unit)? {
    
    // 通过类名获取类对象
    return if (classAvailable(fragmentClassName) &&
      classAvailable(watcherClassName)
    ) {
      val watcherConstructor =
       // 获取构造方法Class.forName(watcherClassName).getDeclaredConstructor(ReachabilityWatcher::class.java)
       // 通过构造方法实例化activity
      @Suppress("UNCHECKED_CAST")
      watcherConstructor.newInstance(reachabilityWatcher) as (Activity) -> Unit
    } else {
      null
    }
  }
  • 2.2.5 AndroidOFragmentDestroyWatcher.kt
@SuppressLint("NewApi")
internal class AndroidOFragmentDestroyWatcher(
  private val reachabilityWatcher: ReachabilityWatcher
) : (Activity) -> Unit {
  private val fragmentLifecycleCallbacks = object : FragmentManager.FragmentLifecycleCallbacks() {
    // 注册onFragmentViewDestoryed监听
    override fun onFragmentViewDestroyed(
      fm: FragmentManager,
      fragment: Fragment
    ) {
      val view = fragment.view
      if (view != null) {
        reachabilityWatcher.expectWeaklyReachable(
          view, "${fragment::class.java.name} received Fragment#onDestroyView() callback " +
          "(references to its views should be cleared to prevent leaks)"
        )
      }
    }

  // 注册onFragmentDestroyed监听
    override fun onFragmentDestroyed(
      fm: FragmentManager,
      fragment: Fragment
    ) {
      reachabilityWatcher.expectWeaklyReachable(
        fragment, "${fragment::class.java.name} received Fragment#onDestroy() callback"
      )
    }
  }

  override fun invoke(activity: Activity) {
    val fragmentManager = activity.fragmentManager
    fragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true)
  }
}

通过前面2.1中我们分析ActivityWatcher我们看到AndroidOFragmentDestroyWatcher中实现与ActivityWatcher基本相似,都是通过ObjectWatcher.kt 中 expectWeaklyReachable方法来实现,这里不再赘述

2.3 RootViewWatcher
  • 2.3.1 RootViewWatcher.kt 中install() 方法
 override fun install() {
    // 2.3.1 添加listener 到Curtains中
    Curtains.onRootViewsChangedListeners += listener
  }

我们看到install方法将listener添加到了Curtains的OnRootViewsChangedListener列表中,而Curtains中onRootViewsChangedListeners记录了root views的数量并在数量发生变更后调用onRootViewsChanged方法

  • 2.3.1 RootViewWatcher.kt 中listener
  private val listener = OnRootViewAddedListener { rootView ->
  // 根据windowType 类型不同判断trackDetached状态
    val trackDetached = when(rootView.windowType) {
      PHONE_WINDOW -> {
        when (rootView.phoneWindow?.callback?.wrappedCallback) {
          // Activities are already tracked by ActivityWatcher
          is Activity -> false
          is Dialog -> rootView.resources.getBoolean(R.bool.leak_canary_watcher_watch_dismissed_dialogs)
          // Probably a DreamService
          else -> true
        }
      }
      // Android widgets keep detached popup window instances around.
      POPUP_WINDOW -> false
      TOOLTIP, TOAST, UNKNOWN -> true
    }
    
    // trackeDetached状态为true,添加rootView的状态变更监听
    if (trackDetached) {
      rootView.addOnAttachStateChangeListener(object : OnAttachStateChangeListener {
        
        // 开启子线程检查rootView引用状态检测是否存在内存泄漏
        val watchDetachedView = Runnable {
           // 这里也是通过objectWatcher进行监视,前面2.1已经分析,同上
          reachabilityWatcher.expectWeaklyReachable(
            rootView, "${rootView::class.java.name} received View#onDetachedFromWindow() callback"
          )
        }
        
        // 根据生命周期回调通过mainHandler处理view事件
        override fun onViewAttachedToWindow(v: View) {
          mainHandler.removeCallbacks(watchDetachedView)
        }

        override fun onViewDetachedFromWindow(v: View) {
          mainHandler.post(watchDetachedView)
        }
      })
    }
  }
  1. 根据rootView的windowType判断是否需要进行track跟踪
  2. 针对需要跟踪的rootView类型开启子线程检查其引用状态,判断是否存在内存泄漏
  3. 针对需要跟踪的rootView生命周期回调,通过mainHandler进行消息传递
2.4 ServiceWatcher
  • 2.4.1 ServiceWatcher.kt 中install()方法
  override fun install() {
  // 主线程检测
    checkMainThread()
    // 非空抛出异常
    check(uninstallActivityThreadHandlerCallback == null) {
      "ServiceWatcher already installed"
    }
    check(uninstallActivityManager == null) {
      "ServiceWatcher already installed"
    }
    try {
     // 转换Activity线程Handler的callback
      swapActivityThreadHandlerCallback { mCallback ->
        uninstallActivityThreadHandlerCallback = {
          swapActivityThreadHandlerCallback {
            mCallback
          }
        }
        Handler.Callback { msg ->
        // 监听what值
          if (msg.what == STOP_SERVICE) {
            val key = msg.obj as IBinder
            activityThreadServices[key]?.let {
            // 2.4.2 预关闭service
              onServicePreDestroy(key, it)
            }
          }
          // 通过callback处理关闭服务消息
          mCallback?.handleMessage(msg) ?: false
        }
      }
      swapActivityManager { activityManagerInterface, activityManagerInstance ->
        uninstallActivityManager = {
          swapActivityManager { _, _ ->
            activityManagerInstance
          }
        }
        // 通过动态代理来获取activityManagerInterface参数
        Proxy.newProxyInstance(
          activityManagerInterface.classLoader, arrayOf(activityManagerInterface)
        ) { _, method, args ->
          if (METHOD_SERVICE_DONE_EXECUTING == method.name) {
            val token = args!![0] as IBinder
            if (servicesToBeDestroyed.containsKey(token)) {
            // 2.4.3 调用serviceDestory关闭回调
              onServiceDestroyed(token)
            }
          }
          try {
            if (args == null) {
              method.invoke(activityManagerInstance)
            } else {
              method.invoke(activityManagerInstance, *args)
            }
          } catch (invocationException: InvocationTargetException) {
            throw invocationException.targetException
          }
        }
      }
    } catch (ignored: Throwable) {
      SharkLog.d(ignored) { "Could not watch destroyed services" }
    }
  }
  • 2.4.2 ServiceWatcher.kt 中onServicePreDestroy()
  private fun onServicePreDestroy(
    token: IBinder,
    service: Service
  ) {
  // 将service变为弱引用状态,便于GC
    servicesToBeDestroyed[token] = WeakReference(service)
  }
  • 2.4.3 ServiceWatcher.kt 中onServiceDestroyed(token)
  private fun onServiceDestroyed(token: IBinder) {
    // 将service从servicesToBeDestroyed集合中移除
    servicesToBeDestroyed.remove(token)?.also { serviceWeakReference ->
      serviceWeakReference.get()?.let { service ->
        // 通过reachabilityWatcher监视内存泄漏的对象,与2.1相同,不再赘述
        reachabilityWatcher.expectWeaklyReachable(
          service, "${service::class.java.name} received Service#onDestroy() callback"
        )
      }
    }
  }
3、流程图

在这里插入图片描述

参考:

LeakCanary
LeakCanary2源码分析

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值