美文网首页
LeakCanary 源码记录 基于V2.7

LeakCanary 源码记录 基于V2.7

作者: 小白彡 | 来源:发表于2022-06-09 22:24 被阅读0次

    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<InstallableWatcher> = 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<InstallableWatcher> {
        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<IBinder, WeakReference<Service>>()
    
      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<IBinder, Service>
      }
    
      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

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