LeakCanary 源码记录 基于V2.7

LeakCanery作为Android中检测内存泄漏的利器, 已经被广泛使用了很长时间了, 核心原理也有很多博文细讲, 大概内容就是,
在对象需要被回收时, 将此对象放入WeakReference中, WeakReference 有个带两个参数的构造函数, 第一个参数是要放入的对象, 第二个参数是一个引用队列,当对象被GC时,当前的WeakReference会被放入到该队列:


图片.png

例如:
当Activity调用onDestory的时候,说明这个Activity需要被回收了, 这个时候把这个Activity放入WeakReference , 再过几秒(GC有间隔时间)检查引用队列中有没有这个WeakReference, 如果有, 说明Activity被回收了, 如果没有,则表示内存泄漏了。

可参考文章:
https://juejin.cn/post/7084115960793137165

这篇文章主要记录, LeakCanary监控“哪些对象“的销毁以及怎么监控这些对象的“销毁时机“,也就是说在什么时候将要销毁的对象放入WeakReference 中观察。

先看结论:
1.Activity : onDestory
2.Fragment:onFragmentViewDestroyed、onFragmentDestroyed
3.View : onViewDetachedFromWindow
4.Service: serviceDoneExecuting

下面再跟着结论,查看源码
LeakCanary新版都不用在Application中初始化了, 转而换成在ContentProvider中初始化, 只需要引入库就直接可用了,很是方便, 那么既然知道了初始化入口,就先出入口开始看起:


图片.png

可以看到,在入口处调用了AppWatcher.manualInstall(application) 方法, 继续跟进

fun manualInstall(
    application: Application,
    retainedDelayMillis: Long = TimeUnit.SECONDS.toMillis(5),
    watchersToInstall: List = appDefaultWatchers(application)
  ) {
    checkMainThread()
    if (isInstalled) {
      throw IllegalStateException(
        "AppWatcher already installed, see exception cause for prior install call", installCause
      )
    }
    check(retainedDelayMillis >= 0) {
      "retainedDelayMillis $retainedDelayMillis must be at least 0 ms"
    }
    installCause = RuntimeException("manualInstall() first called here")
    this.retainedDelayMillis = retainedDelayMillis
    if (application.isDebuggableBuild) {
      LogcatSharkLog.install()
    }
    // Requires AppWatcher.objectWatcher to be set
    LeakCanaryDelegate.loadLeakCanary(application)

    watchersToInstall.forEach {
      it.install()
    }
  }

前面都是一些前置判断, 对吼的循环才是重点, 而循环的值是一个默认值, 看一下默认值有什么:

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

可以看到, 默认值里有四个Watcher, 这四个Watcher就对应了要观察什么对象, 和上面的结论对应了, 接下来就看他们各自怎么监控对象的销魂时机的

1.Activity


图片.png

可以看到,LeakCanary通过注册全局生命周期监听, 在OnDestory时监控Activity是否被GC

2.Fragment


图片.png

FragmentAndViewModelWatcher用一个变量fragmentDestroyWatchers存储了三个 参数为Activity无返回值的方法, 这三个方法分别是什么呢?
第一个:

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) {
        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
    ) {
      reachabilityWatcher.expectWeaklyReachable(
        fragment, "${fragment::class.java.name} received Fragment#onDestroy() callback"
      )
    }
  }

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

这个类实现了一个Function的接口, 重写了invoke方法, 放此方法被调用时, 此Fragment会注册一个全局生命周期监听,在onFragmentViewDestroyed时,监控Fragment的视图View是否被GC, 在onFragmentDestroyed监控Fragment是否被GC。

第二个、第三个:


图片.png

后两个调用的是同一个方法,方法里面根据参数来生成不同的类, 那么看看这两个类是什么:


图片.png

图片.png
图片.png

这两个类的作用其实和第一个一样, 从名称就可以看出,这两个类只是用来适配AndroidX和Support包的。

3.View

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

  private val listener = OnRootViewAddedListener { rootView ->
    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
    }
    if (trackDetached) {
      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)
        }
      })
    }
  }

  override fun install() {
    Curtains.onRootViewsChangedListeners += listener
  }

  override fun uninstall() {
    Curtains.onRootViewsChangedListeners -= listener
  }
}

View也是类似, 通过监听View的AttachState, 在onViewDetachedFromWindow时, 监控View是否被GC, 不过此处用了mainHandler将操作post到了主线程中执行。

4.Service

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

  private val servicesToBeDestroyed = WeakHashMap>()

  private val activityThreadClass by lazy { Class.forName("android.app.ActivityThread") }

  private val activityThreadInstance by lazy {
    activityThreadClass.getDeclaredMethod("currentActivityThread").invoke(null)!!
  }

  private val activityThreadServices by lazy {
    val mServicesField =
      activityThreadClass.getDeclaredField("mServices").apply { isAccessible = true }

    @Suppress("UNCHECKED_CAST")
    mServicesField[activityThreadInstance] as Map
  }

  private var uninstallActivityThreadHandlerCallback: (() -> Unit)? = null
  private var uninstallActivityManager: (() -> Unit)? = null

  override fun install() {
    checkMainThread()
    check(uninstallActivityThreadHandlerCallback == null) {
      "ServiceWatcher already installed"
    }
    check(uninstallActivityManager == null) {
      "ServiceWatcher already installed"
    }
    try {
      swapActivityThreadHandlerCallback { mCallback ->
        uninstallActivityThreadHandlerCallback = {
          swapActivityThreadHandlerCallback {
            mCallback
          }
        }
        Handler.Callback { msg ->
          if (msg.what == STOP_SERVICE) {
            val key = msg.obj as IBinder
            activityThreadServices[key]?.let {
              onServicePreDestroy(key, it)
            }
          }
          mCallback?.handleMessage(msg) ?: false
        }
      }
      swapActivityManager { activityManagerInterface, activityManagerInstance ->
        uninstallActivityManager = {
          swapActivityManager { _, _ ->
            activityManagerInstance
          }
        }
        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)) {
              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" }
    }
  }

  override fun uninstall() {
    checkMainThread()
    uninstallActivityManager?.invoke()
    uninstallActivityThreadHandlerCallback?.invoke()
    uninstallActivityManager = null
    uninstallActivityThreadHandlerCallback = null
  }

  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 ->
        reachabilityWatcher.expectWeaklyReachable(
          service, "${service::class.java.name} received Service#onDestroy() callback"
        )
      }
    }
  }

  private fun swapActivityThreadHandlerCallback(swap: (Handler.Callback?) -> Handler.Callback?) {
    val mHField =
      activityThreadClass.getDeclaredField("mH").apply { isAccessible = true }
    val mH = mHField[activityThreadInstance] as Handler

    val mCallbackField =
      Handler::class.java.getDeclaredField("mCallback").apply { isAccessible = true }
    val mCallback = mCallbackField[mH] as Handler.Callback?
    mCallbackField[mH] = swap(mCallback)
  }

  @SuppressLint("PrivateApi")
  private fun swapActivityManager(swap: (Class<*>, Any) -> Any) {
    val singletonClass = Class.forName("android.util.Singleton")
    val mInstanceField =
      singletonClass.getDeclaredField("mInstance").apply { isAccessible = true }

    val singletonGetMethod = singletonClass.getDeclaredMethod("get")

    val (className, fieldName) = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
      "android.app.ActivityManager" to "IActivityManagerSingleton"
    } else {
      "android.app.ActivityManagerNative" to "gDefault"
    }

    val activityManagerClass = Class.forName(className)
    val activityManagerSingletonField =
      activityManagerClass.getDeclaredField(fieldName).apply { isAccessible = true }
    val activityManagerSingletonInstance = activityManagerSingletonField[activityManagerClass]

    // Calling get() instead of reading from the field directly to ensure the singleton is
    // created.
    val activityManagerInstance = singletonGetMethod.invoke(activityManagerSingletonInstance)

    val iActivityManagerInterface = Class.forName("android.app.IActivityManager")
    mInstanceField[activityManagerSingletonInstance] =
      swap(iActivityManagerInterface, activityManagerInstance!!)
  }

  companion object {
    private const val STOP_SERVICE = 116

    private const val METHOD_SERVICE_DONE_EXECUTING = "serviceDoneExecuting"
  }
}

ServiceWatcher内容比较多, 慢慢看
在install的时候, 先调用了swapActivityThreadHandlerCallback方法


图片.png

图片.png

图片.png

这个方法的作用就是,先通过反射,获取到ActivityThread中的mH, 这个mH是ActivityThread用来处理消息的Handler, 然后将这个Handler中的CallBack替换成自己写的CallBack:

mCallbackField[mH] = swap(mCallback)

替换以后, 这个Handler接收的消息,都会被自己写的CallBack拦截, 从而可以根据消息类型进行想要的操作:
自己写的CallBack, 根据msg.what执行操作:


图片.png

图片.png

116这个值,是停止服务时会收到的, 可以在ActivityThread中找到对应的地方:


图片.png

然而在接收到stopService消息之后, 还没有进行回收监控,只是调用了onServicePreDestroy, 将这个IBinder放进了集合里


图片.png

继续往下:


图片.png

接着调用了swapActivityManager方法:


图片.png

这个方法主要干了三件事:
1.实例化一个ActivityManager (通过单例获取,保证对象唯一性)
2.获取IActivityManager接口
3.将ActivityManager 中的mInstance替换成自己写的Manager

然后通过动态代理的方式, 代理IActivityManager中的serviceDoneExecuting方法


图片.png

图片.png

而serviceDoneExecuting方法,在ActivityThread接到stopService的指令后,会在处理方法中调用, 而且在Service调用完onDestory后:


图片.png

到这一步,表示Service需要被回收了, 于是调用onServiceDestroyed监控Service是否被GC。


图片.png

总的来看,相对复杂的就是Service的监控,其他都是常见的监听生命周期的方式。。。。

记录完。

你可能感兴趣的:(LeakCanary 源码记录 基于V2.7)