LeakCanary2.6抽丝剥茧-源码分析

旧事重提-1.6.3版本和2.6版本的对比

作为一个小Android,之前分析项过目中LeakCanary1.6.3的源码,今天在好奇心的驱使下,刷新了下maven发现,LeakCanary已经更新到2.6版本,今天对2.6的版本也进行源码的解析。

内存泄露分析原理:还是不变的-可达性分析法 :根据是否被GC Root引用确认是否是垃圾对象要被GC回收

gc root.png

2.6版本跟踪内存泄露的核心原理和1.6.3版本是一样的,依赖核心理论-利用weakReference中的数据在gc后是否被添加到ReferenceQueue队列中

使用上的区别

  • 1.6.3使用需要添加依赖和在Application进行注册

gradle的依赖:

debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.3'
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.3'

Application的调用

public class ExampleApplication extends Application {

  @Override

  public void onCreate() {
    super.onCreate();
    //注册
    LeakCanary.install(this);
  }

}
  • 2.6只需要在gradle中添加下依赖就行
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.6'
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:2.6.'

实现语言的区别

  1. 1.6.3版本是使用Java语言
  2. 2.x版本开始都是使用kotlin语言

路径分析库的区别

  1. 1.6.3版本内存泄漏引用路径分析库是haha
  2. 2.6版本内存泄漏引用路径分析库替换成shark库,据说减少了90%内存占用,速度提升了6倍

注册的区别

  1. 1.6.3版本是需要开发者手动在Application.onCreate()方法中进行注册
  2. 2.6版本LeakCanary是使用ContentProvider直接配置在AndroidManifest.xml(不需要手动添加,apk打包会自动配置到)

开始解刨

根据上面的描述,2.6版本是LeakCanary 自动通过ContentProvider注册监听(ContentProvider 会在应用启动前创建)

可以在

2.6版本的LeakCanary的ContentProvider的入口配置位置

源码如下:

 <provider
            android:name="leakcanary.internal.AppWatcherInstaller$MainProcess"
            android:authorities="${applicationId}.leakcanary-installer"
            android:enabled="@bool/leak_canary_watcher_auto_install"
            android:exported="false" />

找到了个入口点,AppWatcherInstaller

internal sealed class AppWatcherInstaller : ContentProvider() {

  ......省略部分代码

  override fun onCreate(): Boolean {

    val application = context!!.applicationContext as Application
    AppWatcher.manualInstall(application)
    return true

  }

  .....省略部分代码

}

查看AppWatcher.kt的manualInstall方法

object AppWatcher {

    .....省略部分代码

  @JvmOverloads

  fun manualInstall(
    application: Application,
    retainedDelayMillis: Long = TimeUnit.SECONDS.toMillis(5),
    watchersToInstall: List<InstallableWatcher> = appDefaultWatchers(application)

  ) {

    //确认是否在主线
    checkMainThread()

    //校验是否重复了
    check(!isInstalled) {
      "AppWatcher already installed"
    }

    check(retainedDelayMillis >= 0) {
      "retainedDelayMillis $retainedDelayMillis must be at least 0 ms"
    }

    this.retainedDelayMillis = retainedDelayMillis
    if (application.isDebuggableBuild) {
      LogcatSharkLog.install()
    }

    // LaekCanary的预设置,通过反射 'leakcanary.internal.InternalLeakCanary'这个类
    LeakCanaryDelegate.loadLeakCanary(application)

    //配置监听(activity,fragment,rootview,service)
    watchersToInstall.forEach {
      it.install()
    }

  }

    .....省略部分代码

}

前面的kotlin函数参数watchersToInstall: List<InstallableWatcher> = appDefaultWatchers(application)

这边实现了activity,fragment,rootview,service的四个监听器,相比1.6.3版本,2.6版本新增了rootview,service的这两个watcher

  fun appDefaultWatchers(
    application: Application,
    reachabilityWatcher: ReachabilityWatcher = objectWatcher
  ): List<InstallableWatcher> {

    return listOf(
      ActivityWatcher(application, reachabilityWatcher),
      FragmentAndViewModelWatcher(application, reachabilityWatcher),
      RootViewWatcher(reachabilityWatcher),
      ServiceWatcher(reachabilityWatcher)
    )

  }

ActivityWatcher,activity的监听还是和1.6.3版本一样是采用监听activity的生命周期,在Destroy的时候,传给ObjectWatcher,做内存泄露的检查,ObjectWatcher在后面会讲到

class ActivityWatcher(

  private val application: Application,
  private val reachabilityWatcher: ReachabilityWatcher

) : InstallableWatcher {

  private val lifecycleCallbacks =

    object : Application.ActivityLifecycleCallbacks by noOpDelegate() {

      override fun onActivityDestroyed(activity: Activity) {

        reachabilityWatcher.expectWeaklyReachable(
          activity, "${activity::class.java.name} received Activity#onDestroy() callback"
        )

      }

    }

  override fun install() {
    application.registerActivityLifecycleCallbacks(lifecycleCallbacks)
  }

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

}

FragmentAndViewModelWatcher在处理fragment的内存泄露,相对在1.6.3版本,LeakCanary针对android.app.Fragment 、support.v4.app.Fragment、androidx.fragment.app.Fragment 三种fragment,分别通过AndroidOFragmentDestroyWatcher、AndroidSupportFragmentDestroyWatcher、AndroidXFragmentDestroyWatcher来进行监听

Fragment的监听,这边以AndroidOFragmentDestroyWatcher来进行讲解,AndroidSupportFragmentDestroyWatcher、AndroidXFragmentDestroyWatcher的流程源码是差不多的

internal class AndroidOFragmentDestroyWatcher(

  private val reachabilityWatcher: ReachabilityWatcher

) : (Activity) -> Unit {

  private val fragmentLifecycleCallbacks = object : FragmentManager.FragmentLifecycleCallbacks() {

    override fun onFragmentViewDestroyed(

      fm: FragmentManager,

      fragment: Fragment

    ) {

      val view = fragment.view

      if (view != null) {

        //在fragment的声明周期执行时,将View对象传给ObjectWatcher
        reachabilityWatcher.expectWeaklyReachable(
          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的声明周期执行时,将fragment对象传给ObjectWatcher
      reachabilityWatcher.expectWeaklyReachable(
        fragment, "${fragment::class.java.name} received Fragment#onDestroy() callback"
      )
    }

  }

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

}

AndroidXFragmentDestroyWatcher这个比较特殊一点是:invoke方法是多了一个viewmodel的监听,

supportFragmentManager,监听Fragment的声明周期,对于Fragment,在onFragmentCreated回调中注册监听,在ViewModel的onCleared回调中监控ViewModel,

在onFragmentDestroyed监听fragment,在onFragmentViewDestroyed监听view

  override fun invoke(activity: Activity) {

    if (activity is FragmentActivity) {
      val supportFragmentManager = activity.supportFragmentManager
      supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true)
      ViewModelClearedWatcher.install(activity, reachabilityWatcher)
    }

  }

fragment又是依赖于activity:

class FragmentAndViewModelWatcher(

  private val application: Application,

  private val reachabilityWatcher: ReachabilityWatcher

) : InstallableWatcher {

  private val fragmentDestroyWatchers: List<(Activity) -> Unit> = run {
    val fragmentDestroyWatchers = mutableListOf<(Activity) -> Unit>()

    if (SDK_INT >= O) {
      fragmentDestroyWatchers.add(
        AndroidOFragmentDestroyWatcher(reachabilityWatcher)
      )

    }

    //Androidx的fragment
    getWatcherIfAvailable(
      ANDROIDX_FRAGMENT_CLASS_NAME,
      ANDROIDX_FRAGMENT_DESTROY_WATCHER_CLASS_NAME,
      reachabilityWatcher
    )?.let {
      fragmentDestroyWatchers.add(it)
    }

    //suport的fragment
    getWatcherIfAvailable(
      ANDROID_SUPPORT_FRAGMENT_CLASS_NAME,
      ANDROID_SUPPORT_FRAGMENT_DESTROY_WATCHER_CLASS_NAME,
      reachabilityWatcher
    )?.let {
      fragmentDestroyWatchers.add(it)
    }

    fragmentDestroyWatchers
  }

  //最终还是依赖于activity的声明周期进行监听,这边的监听是在onActivityCreated这个生命周期方法执行的时候

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

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

  //反射的方式获取AndroidSupportFragmentDestroyWatcher、AndroidXFragmentDestroyWatcher来进行监听

  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)

      @Suppress("UNCHECKED_CAST")
      watcherConstructor.newInstance(reachabilityWatcher) as (Activity) -> Unit
    } else {
      null
    }

  }

 ......省略了部分代码

}

RootViewWatcher:view的内存泄露监听,必须在api是19或者19以上的系统,才支持,通过OnAttachStateChangeListener.onViewDetachedFromWindow()来监听view对象是否内存泄露

class RootViewWatcher(
  private val reachabilityWatcher: ReachabilityWatcher
) : InstallableWatcher {

  override fun install() {
    if (Build.VERSION.SDK_INT < 19) {
      return
    }

    swapViewManagerGlobalMViews { mViews ->

      object : ArrayList<View>(mViews) {

        override fun add(element: View): Boolean {

          onRootViewAdded(element)
          return super.add(element)

        }

      }

    }

  }

  private fun onRootViewAdded(rootView: View) {

    rootView.addOnAttachStateChangeListener(object : OnAttachStateChangeListener {

      val watchDetachedView = Runnable {

        reachabilityWatcher.expectWeaklyReachable(

          rootView, "${rootView::class.java.name} received View#onDetachedFromWindow() callback"

        )

      }

      override fun onViewAttachedToWindow(v: View) {

        mainHandler.removeCallbacks(watchDetachedView)

      }

      override fun onViewDetachedFromWindow(v: View) {

        mainHandler.post(watchDetachedView)

      }

    })

  }

}

ServiceWatcher:通过hook mH回调的service的onDestroy的方法,将该service保存到activityThreadServices。hook AMS,当调用了serviceDoneExecuting方法时,判断service是否出现泄漏

  override fun install() {

    checkMainThread()

    check(uninstallActivityThreadHandlerCallback == null) {
      "ServiceWatcher already installed"
    }

    check(uninstallActivityManager == null) {
      "ServiceWatcher already installed"
    }

    try {

      //hook mH 的callback

      swapActivityThreadHandlerCallback { mCallback ->

        uninstallActivityThreadHandlerCallback = {
          swapActivityThreadHandlerCallback {
            mCallback
          }

        }

        Handler.Callback { msg ->

          ///当调用了service 的onDestroy时
          if (msg.what == STOP_SERVICE) {
            val key = msg.obj as IBinder
            activityThreadServices[key]?.let {
              //将这个service通过弱引用的方式保存到servicesToBeDestroyed中
              onServicePreDestroy(key, it)
            }

          }

          mCallback?.handleMessage(msg) ?: false

        }

      }

      //继续hook,这里hook的是ActivityManagerService
      swapActivityManager { activityManagerInterface, activityManagerInstance ->
        uninstallActivityManager = {
          swapActivityManager { _, _ ->
            activityManagerInstance
          }
        }

        //动态代理的方式
        Proxy.newProxyInstance(
          activityManagerInterface.classLoader, arrayOf(activityManagerInterface)
        ) { _, method, args ->

          //当调用serviceDoneExecuting方法时,观察这个service的泄漏情况
          if (METHOD_SERVICE_DONE_EXECUTING == method.name) {

            //通过token获取service
            val token = args!![0] as IBinder
            if (servicesToBeDestroyed.containsKey(token)) {
              //观察service泄漏情况
              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" }
    }

  }

  private fun onServicePreDestroy(
    token: IBinder,
    service: Service
  ) {
    servicesToBeDestroyed[token] = WeakReference(service)
  }

  private fun onServiceDestroyed(token: IBinder) {
    servicesToBeDestroyed.remove(token)?.also { serviceWeakReference ->
      serviceWeakReference.get()?.let { service ->
        //传给ObjectWatcher去检查内存泄露
        reachabilityWatcher.expectWeaklyReachable(
          service, "${service::class.java.name} received Service#onDestroy() callback"
        )
      }
    }
  }

LeakCanaryDelegate.loadLeakCanary(application)是LaekCanary的预设置,通过反射 'leakcanary.internal.InternalLeakCanary'这个类

InternalLeakCanary.invoke方法是对内存泄露后续对确认和路径分析进行 初始化

internal object LeakCanaryDelegate {

  val loadLeakCanary by lazy {
    try {
      val leakCanaryListener = Class.forName("leakcanary.internal.InternalLeakCanary")
      leakCanaryListener.getDeclaredField("INSTANCE")
        .get(null) as (Application) -> Unit
    } catch (ignored: Throwable) {
      NoLeakCanary
    }
  }
}

开始讲解ObjectWatcher:

class ObjectWatcher constructor(
  private val clock: Clock,
  private val checkRetainedExecutor: Executor,
  //是否忽略
  private val isEnabled: () -> Boolean = { true }
) : ReachabilityWatcher {

  //保留对象的监听(内存泄露对象的通知监听)
  private val onObjectRetainedListeners = mutableSetOf<OnObjectRetainedListener>()

  //KeyedWeakReference的合集,用来存放可能内存泄露的KeyedWeakReference
  private val watchedObjects = mutableMapOf<String, KeyedWeakReference>()

  //弱引用对象被回收的数据存放队列
  private val queue = ReferenceQueue<Any>()

  ......省略了部分代码

  @Synchronized fun addOnObjectRetainedListener(listener: OnObjectRetainedListener) {
    onObjectRetainedListeners.add(listener)
  }

  @Synchronized fun removeOnObjectRetainedListener(listener: OnObjectRetainedListener) {
    onObjectRetainedListeners.remove(listener)
  }

  //核心方法, watchedObject:就是监听activity,fragment、view、service这些对象
  @Synchronized override fun expectWeaklyReachable(
    watchedObject: Any,
    description: String
  ) {

    //是否不进行内存泄露检查
    if (!isEnabled()) {
      return
    }

    //清除掉非内存泄露的对象
    removeWeaklyReachableObjects()

    //生成唯一key
    val key = UUID.randomUUID()
      .toString()

    //监听时间
    val watchUptimeMillis = clock.uptimeMillis()

    //生成KeyedWeakReference对象
    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"
    }

    //放到watchedObjects集合中
    watchedObjects[key] = reference
    checkRetainedExecutor.execute {
      moveToRetained(key)
    }
  }

  .......省略部分代码

  //传递这个内存泄露嫌疑的对象,回调给InternalLeakCanary进行手动gc,再一次确认
  @Synchronized private fun moveToRetained(key: String) {

    removeWeaklyReachableObjects()
    val retainedRef = watchedObjects[key]
    if (retainedRef != null) {
      retainedRef.retainedUptimeMillis = clock.uptimeMillis()
      onObjectRetainedListeners.forEach { it.onObjectRetained() }
    }
  }

  //移除掉非内存泄露的对象
  private fun removeWeaklyReachableObjects() {

    do {
      ref = queue.poll() as KeyedWeakReference?
      if (ref != null) {
        watchedObjects.remove(ref.key)
      }
    } while (ref != null)
  }

}

解释上,上面onObjectRetainedListeners的回调为什么回回调到InternalLeakCanary中,前面我们提到LeakCanaryDelegate.loadLeakCanary(application)是LeakCanary的预设置,通过反射 'leakcanary.internal.InternalLeakCanary'这个类,调用了invoke这个方法

internal object InternalLeakCanary : (Application) -> Unit, OnObjectRetainedListener {

  ......省略代码

  override fun invoke(application: Application) {

    _application = application
    checkRunningInDebuggableBuild()

    //这边添加了OnObjectRetainedListener的监听,让InternalLeakCanary实现了OnObjectRetainedListener接口
    AppWatcher.objectWatcher.addOnObjectRetainedListener(this)

    //创建AndroidHeapDumper对象,用来进行内存泄露分析的通知和toast提示
    val heapDumper = AndroidHeapDumper(application, createLeakDirectoryProvider(application))

    //gc和1.6.3版本一样的实现,只是代码是用kotlin写的
    val gcTrigger = GcTrigger.Default
    val configProvider = { LeakCanary.config }
    val handlerThread = HandlerThread(LEAK_CANARY_THREAD_NAME)
    handlerThread.start()
    val backgroundHandler = Handler(handlerThread.looper)

    //路径分析的触发器,手动gc的触发checkRetainedObjects()
    heapDumpTrigger = HeapDumpTrigger(
      application, backgroundHandler, AppWatcher.objectWatcher, gcTrigger, heapDumper,
      configProvider
    )

    //activity的声明周期监听
    application.registerVisibilityListener { applicationVisible ->

      this.applicationVisible = applicationVisible
      heapDumpTrigger.onApplicationVisibilityChanged(applicationVisible)

    }

    registerResumedActivityListener(application)

    //动态增加LeakCanary的桌面图标
    addDynamicShortcut(application)

    // 日志输出,在Application.onCreate()执行后ß
    mainHandler.post {

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

        }

      }

    }

  }

  override fun onObjectRetained() = scheduleRetainedObjectCheck()

  ......省略代码

}

继之前的 ObjectWatcher的OnObjectRetainedListener.onObjectRetained() ,回调到InternalLeakCanary中实现的onObjectRetained() 方法

//转交给heapDumpTrigger去进行处理
fun scheduleRetainedObjectCheck() {
    if (this::heapDumpTrigger.isInitialized) {
      heapDumpTrigger.scheduleRetainedObjectCheck()
    }
  }

转到HeapDumpTrigger的scheduleRetainedObjectCheck()方法

internal class HeapDumpTrigger(

  private val application: Application,

  private val backgroundHandler: Handler,

  private val objectWatcher: ObjectWatcher,

  private val gcTrigger: GcTrigger,

  private val heapDumper: HeapDumper,

  private val configProvider: () -> Config

) {

  .......省略部分代码

  private fun checkRetainedObjects() {

    val iCanHasHeap = HeapDumpControl.iCanHasHeap()

    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) {
          //触发GC
          gcTrigger.runGc()
          retainedReferenceCount = objectWatcher.retainedObjectCount
        }

        val nopeReason = iCanHasHeap.reason()

        // 如果内存泄漏对象数量在阈值内,不生成dump文件分析
        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,进行一次手动的gc
    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

    }

    dismissRetainedCountNotification()
    val visibility = if (applicationVisible) "visible" else "not visible"

    dumpHeap(
      retainedReferenceCount = retainedReferenceCount,
      retry = true,
      reason = "$retainedReferenceCount retained objects, app is $visibility"
    )

  }

  private fun checkRetainedCount(
    retainedKeysCount: Int,
    retainedVisibleThreshold: Int,
    nopeReason: String? = null
  ): Boolean {

    //检查最新的保留对象数量(内存泄露对象)数量是否发生变化
    val countChanged = lastDisplayedRetainedObjectCount != retainedKeysCount
    lastDisplayedRetainedObjectCount = retainedKeysCount

    //当数量是0,通知没有内存泄漏
    if (retainedKeysCount == 0) {

      if (countChanged) {
        SharkLog.d { "All retained objects have been garbage collected" }
        onRetainInstanceListener.onEvent(NoMoreObjects)
        showNoMoreRetainedObjectNotification()
      }

      return true

    }

    val applicationVisible = applicationVisible
    val applicationInvisibleLessThanWatchPeriod = applicationInvisibleLessThanWatchPeriod
    if (countChanged) {

      val whatsNext = if (applicationVisible) {

        if (retainedKeysCount < retainedVisibleThreshold) {
          "not dumping heap yet (app is visible & < $retainedVisibleThreshold threshold)"
        } else {
          if (nopeReason != null) {
            "would dump heap now (app is visible & >=$retainedVisibleThreshold threshold) but $nopeReason"
          } else {
            "dumping heap now (app is visible & >=$retainedVisibleThreshold threshold)"
          }

        }

      } else if (applicationInvisibleLessThanWatchPeriod) {
        val wait =
          AppWatcher.config.watchDurationMillis - (SystemClock.uptimeMillis() - applicationInvisibleAt)
        if (nopeReason != null) {
          "would dump heap in $wait ms (app just became invisible) but $nopeReason"
        } else {
          "dumping heap in $wait ms (app just became invisible)"
        }
      } else {
        if (nopeReason != null) {
          "would dump heap now (app is invisible) but $nopeReason"
        } else {
          "dumping heap now (app is invisible)"
        }
      }

      SharkLog.d {
        val s = if (retainedKeysCount > 1) "s" else ""
        "Found $retainedKeysCount object$s retained, $whatsNext"
      }

    }

    // 如果内存泄露对象数量右边,且当前应用是可见的(在前台显示),则显示数量通知
    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
          )
        )

        scheduleRetainedObjectCheck(
          delayMillis = WAIT_FOR_OBJECT_THRESHOLD_MILLIS
        )
        return true
      }
    }
    return false
  }

  //计划对保留的对象进行进步一步检查
  fun scheduleRetainedObjectCheck(
    delayMillis: Long = 0L
  ) {
    val checkCurrentlyScheduledAt = checkScheduledAt
    if (checkCurrentlyScheduledAt > 0) {
      return
    }

    checkScheduledAt = SystemClock.uptimeMillis() + delayMillis
    backgroundHandler.postDelayed({
      checkScheduledAt = 0
      checkRetainedObjects()
    }, delayMillis)

  }

  //通知提示没有更多的内存泄露信息
  private fun showNoMoreRetainedObjectNotification() {

    backgroundHandler.removeCallbacks(scheduleDismissRetainedCountNotification)
    if (!Notifications.canShowNotification) {
      return
    }

    val builder = Notification.Builder(application)
      .setContentTitle(
        application.getString(R.string.leak_canary_notification_no_retained_object_title)
      )
      .setContentText(
        application.getString(
          R.string.leak_canary_notification_no_retained_object_content
        )
      )
      .setAutoCancel(true)
      .setContentIntent(NotificationReceiver.pendingIntent(application, CANCEL_NOTIFICATION))

    val notification =
      Notifications.buildNotification(application, builder, LEAKCANARY_LOW)
    notificationManager.notify(R.id.leak_canary_notification_retained_objects, notification)

    backgroundHandler.postDelayed(
      scheduleDismissRetainedCountNotification, DISMISS_NO_RETAINED_OBJECT_NOTIFICATION_MILLIS
    )
  }

  //通知告知有多少个内存泄露的信息
  private fun showRetainedCountNotification(
    objectCount: Int,
    contentText: String
  ) {

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

  .......省略部分代码

}

通过以上的代码,可以看出HeapDumpTrigger实际上做了两件事

  1. 通过objectWatcher.retainedObjectCount的数量和阀值进行对比,判断是否需要生成dump文件
  2. 通过gc再一次生成,再一次确认了内存泄露的数量,即objectWatcher.retainedObjectCount值,确实是否需要dump文件和通知
    这也是和1.6.3版本不一样的地方,旧版本是只要有泄露都会进行dump
    最后dump的过程是和旧版基本是一样的,这边不做分析了。

可以参考下时序图:

LeakCanary2.6.png

回顾

  • LeakCanary是如何简化了sdk的接入?
  1. 2.6版本相对1.6.3版本,只需要一行依赖配置代码即可,2.6采用ContentProvider,ContentProvider的onCreate的调用时机是在application onCreate之前调用的,减少了接入的成本
  2. 通过占位符的方式,简化了接入方在manifest文件上的接入成本,在编译打包的时候,会将AppWatcherInstaller合并到AndroidManifest中
  • LeakCanary 触发去判断是否存在内存泄露的时机
  1. Activity:通过在Application中注册registerActivityLifecycleCallbacks绑定Activity生命周期回调,并在onActivityDestroyed回调中监控Activity
  2. Fragment:通过在Application中注册registerActivityLifecycleCallbacks绑定Activity生命周期回调,并在onActivityCreated回调中,通过在Activity中注册注册FragmentLifecycleCallbacks回调,并在onFragmentDestroyed回调时,监控fragment或者view。androidx的frogment是 针对AndroidX库中的Activity,对于Activity,在onActivityCreated回调中注册监听,对于Fragment,在onFragmentCreated回调中注册监听,在ViewModel的onCleared回调中监控ViewModel
  3. View:只作用于android>=19, 通过View.addOnAttachStateChangeListener注册view的声明周期,并在onViewDetachedFromWindow()来监听view对象是否内存泄露
  4. Service:通过hook mH回调的service的onDestroy的方法,将该service保存到activityThreadServices。hook AMS,当调用了serviceDoneExecuting方法时,判断service是否出现泄漏
  • 判断内存泄露的原理
  1. 是利用了WeakRefrence + RefrenceQueue的机制(仅被弱引用持有的对象,当对象被回收时,会存入到引用队列中),从引用队列中不断的获取对象,将已确认被GC的对象剔除,剩余未被回收的对象则定义为可能泄露的对象,当达到一定的判断条件时,通知用户内存泄露
本站文章资源均来源自网络,除非特别声明,否则均不代表站方观点,并仅供查阅,不作为任何参考依据!
如有侵权请及时跟我们联系,本站将及时删除!
如遇版权问题,请查看 本站版权声明
THE END
分享
二维码
海报
LeakCanary2.6抽丝剥茧-源码分析
作为一个小Android,之前分析项过目中LeakCanary1.6.3的源码,今天在好奇心的驱使下,刷新了下maven发现,LeakCanary已经更新到2....
<<上一篇
下一篇>>