当前位置: 首页 > 工具软件 > LeakCanary > 使用案例 >

Android---LeakCanary源码分析

祁博雅
2023-12-01

LeakCanary不用多说,学过Android的同学都知道它。LeakCanary2.x相对于LeakCanary1.x有两个比较明显的改变:(1)源码全部使用了Kotlin进行编写(2)不需要再Application中进行install操作。今天我就从LeakCanary的启动以及各个对象的回收监听两个方面来解析这个框架

一、LeakCanary的启动

上面我们说了,2.x的版本,我们不用在Application中调用install方法了,那LeakCanary是如何启动的呢?

首先,我们先找到AppWatcherInstaller.kt这个文件,代码如下:

internal sealed class AppWatcherInstaller : ContentProvider() {

  internal class LeakCanaryProcess : AppWatcherInstaller()

  override fun onCreate(): Boolean {
    val application = context!!.applicationContext as Application
    AppWatcher.manualInstall(application)
    return true
  }
  ....  
}

我们发现,AppWatcherInstaller这个类继承自ContentProvider。了解ContentProvider的同学都知道,ContentProvider注册即执行。而AppWatcherInstaller的注册就是在leakcanary-object-watcher-android文件夹的AndroidManifest.xml中,我们找到如下的代码:

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

当执行打包指令时,所有的AndroidManifest.xml会合并到一起。所以我们不需要再Application中调用install方法了

二、各个对象的监听

目前,LeakCanary默认可以监听Activity,Fragment,ViewModel,Service。接下来我们会一一介绍

我们先回到AppWatcherInstaller的onCreate方法里,这里调用了AppWatcher的manualInstall方法,我们看一下:

  @JvmOverloads
  fun manualInstall(
    application: Application,
    retainedDelayMillis: Long = TimeUnit.SECONDS.toMillis(5),
    watchersToInstall: List<InstallableWatcher> = appDefaultWatchers(application)
  ) {
    checkMainThread()
    ......
    LeakCanaryDelegate.loadLeakCanary(application)

    watchersToInstall.forEach {
      it.install()
    }
  }

第7行:主线程的校验,没什么说的

第9行:我们先点击loadLeakCanary,进入看看

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

首先进行了反射,拿到了InternalLeakCanary对象,然后调用了get方法,最后强转为一个lamda表达式。

我们先回到AppWatcher的manualInstall方法中,我们现在只需要记住,执行了LeakCanaryDelegate.loadLeakCanary,就执行了InternalLeakCanary的invoke方法就可以了,引用另一篇博客的解释:

我们创建InternalAppWatcher时init方法就会调用,onAppWatcherInstalled是kotlin中invoke约定的应用可以将invoke函数的lambda表达式赋值给一个变量,
Kotlin的约定有很多种,而比如使用便捷的get操作,以及重载运算符等等,invoke约定也仅仅是一种约定而已;
我们可以把lambda表达式或者函数直接保存在一个变量中,然后就像执行函数一样直接执行这个变量,
这样的变量通常声明的时候都被我们赋值了已经直接定义好的lambda,或者通过成员引用而获取到的函数;
但是别忘了,在面向对象编程中,一个对象在通常情况下都有自己对应的类,那我们能不能定义一个类,
然后通过构造方法来产生一个对象,然后直接执行它呢?这正是invoke约定发挥作用的地方。
我们只需要在一个类中使用operator来修饰invoke函数,这样的类的对象就可以直接像一个保存lambda表达式的变量一样直接调用,而调用后执行的函数就是invoke函数。
我们还有另一种方式来实现可调用的对象,即让类继承自函数类型,然后重写invoke方法。
————————————————
版权声明:本文为CSDN博主「Darksiderl」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u011148116/article/details/106762665/

第5行:这里执行了appDefaultWatchers方法,然后将返回值赋值给了watchersToInstall,在第11行中,对这个变量进行了遍历,执行了每个元素的install方法。我们看一下appDefaultWatchers方法:

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

在这里,我们可以看见了很多眼熟的单词:Activity,Fragment,ViewModel,RootView,Service。这些就是LeakCanary默认监听的对象,我们一个一个来介绍:

1.Activity的监听过程

我们先看一下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) {
        reachabilityWatcher.expectWeaklyReachable(
          activity, "${activity::class.java.name} received Activity#onDestroy() callback"
        )
      }
    }

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

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

lifecycleCallbacks就是Application.ActivityLifecycleCallbacks,主要用来进行进行Activity生命周期监听的。install和uninstall方法分别进行了注册和解注册。

在lifecycleCallbacks创建过程中,只实现了onActivityDestroyed方法,当Activity销毁的时候,会回调到这里。然后执行了ReachabilityWatcher对象的expectWeaklyReachable方法,这个方法的具体实现是在ObjectWatcher中,我们看一下:

  @Synchronized override fun expectWeaklyReachable(
    watchedObject: Any,
    description: String
  ) {
    if (!isEnabled()) {
      return
    }
    removeWeaklyReachableObjects()
    val key = UUID.randomUUID()
      .toString()
    val watchUptimeMillis = clock.uptimeMillis()
    val reference =
      KeyedWeakReference(watchedObject, key, description, watchUptimeMillis, queue)

    watchedObjects[key] = reference
    checkRetainedExecutor.execute {
      moveToRetained(key)
    }
  }

第8行:我们先看一下这个方法

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

所表达的意思是:从引用队里中取数据,如果有数据,表示这个数据被回收了,那么从被观察的集合中移除,此时ref不为空,所以还会循环;如果ref等于空,表示没有对象回收,则直接跳出循环。watchedObjects是Map,里面的数据就是被观察的对象。

在回到ReachabilityWatcher的expectWeaklyReachable方法:

第9~13行:根据uuid创建了key,拿到时间,然后创建一个弱引用对象

第15行:以uuid创建的key为map的键,弱引用对象为值,进行存储

第17行:在子线程中,执行了moveToRetained方法,我们进去看看:

  @Synchronized private fun moveToRetained(key: String) {
    removeWeaklyReachableObjects()
    val retainedRef = watchedObjects[key]
    if (retainedRef != null) {
      retainedRef.retainedUptimeMillis = clock.uptimeMillis()
      onObjectRetainedListeners.forEach { it.onObjectRetained() }
    }
  }

第2行:这里有再次执行了removeWeaklyReachableObjects方法,重新对阻塞队列里的值进行确认,看看有没有被回收的对象

第3~7行:根据key拿到相应的弱引用,然后遍历onObjectRetainedListeners集合,执行每个元素的onObjectRetained方法。

这里可能有些同学不知道这里集合的数据是什么时候添加的,上面我们说过InternalLeakCanary的invoke方法,这个方法里有如下一句代码:

AppWatcher.objectWatcher.addOnObjectRetainedListener(this)

其实就是在invoke方法中添加的,而集合中的元素也就是InternalLeakCanary,所以执行的onObjectRetained方法也是在这个类中,我们查看这个方法:

  override fun onObjectRetained() = scheduleRetainedObjectCheck()

  fun scheduleRetainedObjectCheck() {
    if (this::heapDumpTrigger.isInitialized) {
      heapDumpTrigger.scheduleRetainedObjectCheck()
    }
  }

heapDumpTrigger是HeapDumpTrigger类,我们查看它的scheduleRetainedObjectCheck方法

  fun scheduleRetainedObjectCheck(
    delayMillis: Long = 0L
  ) {
    val checkCurrentlyScheduledAt = checkScheduledAt
    if (checkCurrentlyScheduledAt > 0) {
      return
    }
    checkScheduledAt = SystemClock.uptimeMillis() + delayMillis
    backgroundHandler.postDelayed({
      checkScheduledAt = 0
      checkRetainedObjects()
    }, delayMillis)
  }

最关键的是第11行代码,我们查看这个方法

private fun checkRetainedObjects() {
    ....

    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
    }

    dismissRetainedCountNotification()
    val visibility = if (applicationVisible) "visible" else "not visible"
    dumpHeap(
      retainedReferenceCount = retainedReferenceCount,
      retry = true,
      reason = "$retainedReferenceCount retained objects, app is $visibility"
    )
  }

代码篇幅不少,我就挑重点介绍一下:

第4~9行:根据被观察的数量,主动进行一次GC

第11行:这个方法其实很重要,但是我们就不进入看了,总结一下主要逻辑就可以了:判断被观察者的数量是否大于0,并且小于5,如果符合这个条件,则弹出提示通知,并且这个方法返回true。如果返回true的话,下面的代码就不执行了。

第13~15行:判断上次弹出通知的时间和现在的差值,如果时间差小于60s,则弹出提示通知,并且下面的内容不再执行

第27~29行:如果上述的条件都没有满足,那么将提示通知关闭,直接进行结果分析。

Activity的监听过程,还是比较简单的

2.Fragment和ViewModel

在AppWatcher的代码中(上面说过),我们知道Fragment和ViewModel的对象监听是在FragmentAndViewModelWatcher.kt这个类中,我们看一下:

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

    getWatcherIfAvailable(
      ANDROIDX_FRAGMENT_CLASS_NAME,
      ANDROIDX_FRAGMENT_DESTROY_WATCHER_CLASS_NAME,
      reachabilityWatcher
    )?.let {
      fragmentDestroyWatchers.add(it)
    }

    getWatcherIfAvailable(
      ANDROID_SUPPORT_FRAGMENT_CLASS_NAME,
      ANDROID_SUPPORT_FRAGMENT_DESTROY_WATCHER_CLASS_NAME,
      reachabilityWatcher
    )?.let {
      fragmentDestroyWatchers.add(it)
    }
    fragmentDestroyWatchers
  }

  private val lifecycleCallbacks =
    object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
      override fun onActivityCreated(
        activity: Activity,
        savedInstanceState: Bundle?
      ) {
        for (watcher in fragmentDestroyWatchers) {
          watcher(activity)
        }
      }
    }
  .....
}

有一些非关键的方法我没贴出来,比如说install,uninstall方法,进行注册和解注册,和ActivityWatcher中的代码一样;getWatcherIfAvailable和classAvailable方法,主要进行了反射相关的操作;

第33行:我们先看一下lifecycleCallbacks,和ActivityWatcher中有些不一样,ActivityWatcher中的lifecycleCallbacks实现的是onActivityDestroyed方法,而这里实现的是onActivityCreated方法。其实很好理解:ActivityWatcher监听的是Activity对象,并且LifecycleCallback监听的也是Activity的生命周期,当Activity销毁的时候,需要判断Activity对象是否释放了;而FragmentAndViewModeWatcher中监听的是Fragment和ViewModel,它们的宿主是Activity,LifecycleCallback监听的也是它们的宿主,所以只有当宿主创建了,才开始Fragment和ViewModel的监听。而Fragment和ViewModel销毁的时候,对象有没有释放的判断,并不是在这里

第39行:我们看到循环了fragmentDestryWatchers,这个列表中的元素是对不同类型的Fragment的回收监听,Fragment有三种类型

(1)非AndroidX中的Fragment,如果SDK的版本大于等于26,那么对Fragment生命周期的监听是Activity的fragmentManager.registerFragmentLifecycleCallbacks方法

(2)非AndroidX中的Fragment,如果SDK的版本小于26,那么对Fragment生命周期的监听是FragmentActivity的supportFragmentManager.registerFragmentLifecycleCallbacks方法

(3)如果是AndroidX的Fragment,那么对Fragment生命周期的监听是AndroidX包下FragmentActivity的supportFragmentManager.registerFragmentLifecycleCallbacks方法

而这三个Fragment的监听者分别是:AndroidOFragmentDestroyWatcher.kt,AndroidXFragmentDestoryWatcher.kt,AndroidSupportFragmentDestroyWatcher.kt。其实这三个关于Fragment的监听没什么区别,只是AndroidXFragmentDestoryWatcher.kt中多了对ViewModel对象的监听,我们主要讲一下AndroidXFragmentDestoryWatcher,其他两个就略过了

internal class AndroidXFragmentDestroyWatcher(
  private val reachabilityWatcher: ReachabilityWatcher
) : (Activity) -> Unit {

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

    override fun onFragmentCreated(
      fm: FragmentManager,
      fragment: Fragment,
      savedInstanceState: Bundle?
    ) {
      ViewModelClearedWatcher.install(fragment, reachabilityWatcher)
    }

    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) {
    if (activity is FragmentActivity) {
      val supportFragmentManager = activity.supportFragmentManager
      supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true)
      ViewModelClearedWatcher.install(activity, reachabilityWatcher)
    }
  }
}

第5行:fragmentLifecycleCallbacks就是Fragment的生命周期回调,

onFragmentDestroyed是对Fragment对象的回收监听,当Fragment销毁的时候,会调用reachabilityWatcher的expectWeaklyReachable方法,和ActivityWatcher中调用的方法一样,具体的逻辑我就不说了,ActivityWatcher的时候已经说过了

onFragmentViewDestroyed是对Fragment中RootView对象的回收监听,当RootView销毁的时候,同样会执行reachabilityWatcher的expectWeaklyReachable方法。这个回调方法在其他两个FragmentWatcher中也是有的。

onFragmentCreated是对ViewModel对象的回收监听,ViewModelClearedWatcher是具体的监听者,我们发现在第12行和第42行都调用了ViewModelClearedWatcher的install方法,但是第一个参数不一样,这表示ViewModel的宿主不一样。一个是Activity,一个是Fragment。

我们看一下ViewModelClearedWatcher的代码:

internal class ViewModelClearedWatcher(
  storeOwner: ViewModelStoreOwner,
  private val reachabilityWatcher: ReachabilityWatcher
) : ViewModel() {

  private val viewModelMap: Map<String, ViewModel>?

  init {
    // We could call ViewModelStore#keys with a package spy in androidx.lifecycle instead,
    // however that was added in 2.1.0 and we support AndroidX first stable release. viewmodel-2.0.0
    // does not have ViewModelStore#keys. All versions currently have the mMap field.
    viewModelMap = try {
      val mMapField = ViewModelStore::class.java.getDeclaredField("mMap")
      mMapField.isAccessible = true
      @Suppress("UNCHECKED_CAST")
      mMapField[storeOwner.viewModelStore] as Map<String, ViewModel>
    } catch (ignored: Exception) {
      null
    }
  }

  override fun onCleared() {
    viewModelMap?.values?.forEach { viewModel ->
      reachabilityWatcher.expectWeaklyReachable(
        viewModel, "${viewModel::class.java.name} received ViewModel#onCleared() callback"
      )
    }
  }

  companion object {
    fun install(
      storeOwner: ViewModelStoreOwner,
      reachabilityWatcher: ReachabilityWatcher
    ) {
      val provider = ViewModelProvider(storeOwner, object : Factory {
        @Suppress("UNCHECKED_CAST")
        override fun <T : ViewModel?> create(modelClass: Class<T>): T =
          ViewModelClearedWatcher(storeOwner, reachabilityWatcher) as T
      })
      provider.get(ViewModelClearedWatcher::class.java)
    }
  }
}

有一个比较关键的点:我们发现ViewModelClearedWatcher继承子ViewModel,也就是说它本身是一个ViewModel。并且实现了onCleared方法,这个方法在ViewModel销毁的时候会执行,和Activity的onDestroy作用一样。

第31行:这里是install方法的具体内容。如果使用过ViewModel的话,这里很容易理解,就是ViewModel和宿主的绑定。而ViewModel就是ViewModelClearedWatcher。

第8~20行:当ViewModelClearedWatcher创建的时候,通过反射拿到宿主的mMap,得到宿主中所有的ViewModel。

第22行:当ViewModelClearedWatcher被销毁时,会执行到onCleared方法,这时候会遍历宿主中所有的ViewModel,执行reachabilityWatcher的expectWeaklyReachable方法,判断ViewModel是否都已经释放了。

这就是Fragment和ViewModel的对象监听过程

3.Service

Android中Service,没有类似Activity和Fragment的生命周期回调监听,所以LeakCanary采用的是Hook的方式,而这里需要我们对Android的源码有一定的了解。首先是ActivityThread,这里面有一个内部类H,继承自Handler,如下:

class H extends Handler {
    .....
}

很多系统指令都会传递到这个类中,其中有一个指令是STOP_SERVICE,也就是说当我们执行stopService时,类H会接收到STOP_SERVICE指令进行Service关闭,如下:

case STOP_SERVICE:
         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceStop");
         handleStopService((IBinder)msg.obj);
         schedulePurgeIdler();
         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
         break;

查看handleStopService方法:

    private void handleStopService(IBinder token) {
        Service s = mServices.remove(token);
        if (s != null) {
            try {
                if (localLOGV) Slog.v(TAG, "Destroying service " + s);
                s.onDestroy();
                s.detachAndCleanUp();
                Context context = s.getBaseContext();
                if (context instanceof ContextImpl) {
                    final String who = s.getClassName();
                    ((ContextImpl) context).scheduleFinalCleanup(who, "Service");
                }

                QueuedWork.waitToFinish();

                try {
                    ActivityManager.getService().serviceDoneExecuting(
                            token, SERVICE_DONE_EXECUTING_STOP, 0, 0);
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            } 
            ......
        }
        ......
    }

 我们可以看到第二行,拿到了Service对象,那么我们拿到这个Service对象,不就可以了吗?

其实现在还不行!因为下面还有Service方法的调用,需要调用第6行到第15行一系列的代码,才能真正的将Service关闭

所以LeakCanary做了两步:第一步:监听STOP_SERVICE指令,拿到被监听的Service;第二步:通过动态代理,获取第17行的serviceDoneExecuting,在此方法执行之前,进行回收的判断。

4.RootView

我们要注意一点,这里是RootView,而不是所有的View,LeakCanary默认只会监听所有的根View。代码我就不贴了,我主要介绍一下思路,个人觉得都是大同小异

  • 销毁的监听:这是做对象监听的必要条件,只有能监听到对象销毁时的监听,才能判断这个对象是否真正的释放了,而View的销毁监听是OnAttachStateChangeListener,这个监听有两个回调方法,当View和Window绑定和取消绑定的时候会执行
  • 对象的获取:如果了解UI绘制的话,就知道所有的RootView都存储在WindowManagerGlobal的mView中,mView是一个集合(SDK小于16的话是在WindowManagerImpl中)

鸣谢:

Android LeakCanary检测内存泄露原理_Android_软件编程 - 编程客栈

Android内存泄漏-LeakCanary源码原理分析_Darksiderl的博客-CSDN博客

 类似资料: