美文网首页
2021-01-22 Leakcanary 源码流程(Activ

2021-01-22 Leakcanary 源码流程(Activ

作者: 猫KK | 来源:发表于2021-01-22 14:27 被阅读0次

    这里是基于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<InstallableWatcher> = 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<InstallableWatcher> = appDefaultWatchers(application)
      ) {
        //...
        //install 方法
        watchersToInstall.forEach {
          it.install()
        }
      }
    

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

      fun appDefaultWatchers(
        application: Application,
        reachabilityWatcher: ReachabilityWatcher = objectWatcher
      ): List<InstallableWatcher> {
        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 源码流程(Activ

          本文链接:https://www.haomeiwen.com/subject/gljszktx.html