Android-LeakCanary原理解析

一、前言(了解ReferenceQueue) 在分析LeakCanary原理之前,首先需要了解ReferenceQueue在LeakCanary的作用。
WeakReference在创建时,如果指定一个ReferenceQueue对象,在垃圾回收检测到被引用的对象的可达性更改后,垃圾回收器会将已注册的引用对象添加到ReferenceQueue对象中,等待ReferenceQueue处理。但是如果当GC过后引用对象仍然不被加入ReferenceQueue中,就可能存在内存泄露问题。这里ReferenceQueue对象中,存的其实就是WeakReference对象,而不是WeakReference中引用的要被回收的对象。即GC过后,WeakReference引用的对象被回收了,那么WeakReference引用的对象就是null,那么该WeakReference对象就会被加入到ReferenceQueue队列中。
所以我们可以通过监听 Activity.onDestroy() 回调之后,通过弱引用(WeakReference)对象、ReferenceQueue和 GC来观测Activity引用的内存泄露情况,如果发现了未被回收的Activity对象,在找到该Activity对象是否被其他对象所引用,如果被其他对象引用,就进行 heap dump生成完整的内存引用链(最短引用链),并通过notification等方式展示出来。
二、LeakCanary的启动 LeakCanary2.+的启动,与LeakCanary1.+的不同,1.+版本的启动,需要在Application的onCreate中手动调用LeakCanary.install方法进行启动;而2.+版本的启动则不需要,而是依赖ContentProvider,因为ContentProvider会在Application之前被加载,所以ContentProvider的onCreate方法会在Application的onCreate方法之前被调用,所以在ContentProvider的onCreate方法中完成初始化工作。
在源码中leakcanary-leaksentry中有一个LeakSentryInstaller,LeakSentryInstaller其实就是ContentProvider的一个子类,在其onCreate方法中就会调用InternalLeakSentry.install(application)进行初始化工作。

internal class LeakSentryInstaller : ContentProvider() {override fun onCreate(): Boolean { CanaryLog.logger = DefaultCanaryLog() val application = context!!.applicationContext as Application InternalLeakSentry.install(application) // 进行初始化工作,核心 return true } ... }

【Android-LeakCanary原理解析】然后在AndroidManifest.xml中注册该ContentProvider。在这里注册,那么打包项目时,会将每个库和library中的AndroidManifest.xml合并到最终的app的androidManifest中。

三、LeakCanary的初始化 LeakCanary的初始化是在InternalLeakSentry的install方法,即在ContentProvider的onCreate中调用。
1.InternalLeakSentry#install
private val mainHandler = Handler(Looper.getMainLooper())init {//构造函数 listener = try {//InternalLeakCanary是继承自LeakSentryListener,然后这里它是一个kotlin单例模式 val leakCanaryListener = Class.forName("leakcanary.internal.InternalLeakCanary") leakCanaryListener.getDeclaredField("INSTANCE").get(null) as LeakSentryListener } catch (ignored: Throwable) { LeakSentryListener.None } }private val checkRetainedExecutor = Executor { // 默认五秒后执行 mainHandler.postDelayed(it, LeakSentry.config.watchDurationMillis) } val refWatcher = RefWatcher( clock = clock, checkRetainedExecutor = checkRetainedExecutor, onReferenceRetained = { listener.onReferenceRetained() }, isEnabled = { LeakSentry.config.enabled } )

fun install(application: Application) { CanaryLog.d("Installing LeakSentry") checkMainThread() // 只能在主线程调用,否则会抛出异常 if (this::application.isInitialized) { return } InternalLeakSentry.application = applicationval configProvider = { LeakSentry.config } // 这里监听页面的销毁 // 在这里会调用RefWatcher.watch()方法监测Activity的引用 // 其中RefWatcher在InternalLeakSentry类中创建。 ActivityDestroyWatcher.install( // 监听 Activity.onDestroy() application, refWatcher, configProvider ) // 在这里会创建多个FragmentDestroyWatcher // 其内部采用单例的方式,用List列表存储FragmentDestroyWatcher // 而具体的FragmentDestroyWatcher其实就是SupportFragmentDestroyWatcher // SupportFragmentDestroyWatcher是其接口实现类 // 这是androidx使用,但是需要fragment可以使用 // FragmentDestroyWatcher中会监听生命周期的onActivityCreated方法 // 遍历所有的FragmentDestroyWatcher,调用其watchFragments方法 // watchFragments方法在SupportFragmentDestroyWatcher的实现,其实就是 // 注册该fragment的生命周期的监听 FragmentDestroyWatcher.install( // 监听 Fragment.onDestroy() application, refWatcher, configProvider ) // 初始化检测内存泄露过程中需要用到的对象 listener.onLeakSentryInstalled(application) // Sentry 哨兵 }

这里的listener是LeakSentryListener接口,而实现LeakSentryListener接口的类,其实就是InternalLeakCanary,InternalLeakCanary是在leakcanary-android-core下的,InternalLeakCanary是单例模式的,采用的是kotlin单例,即用object关键字修饰类。
2.InternalLeakCanary#onLeakSentryInstalled
override fun onLeakSentryInstalled(application: Application) { this.application = application// 用于 heap dump:堆转储 val heapDumper = AndroidHeapDumper(application, leakDirectoryProvider) val gcTrigger = GcTrigger.Default // 用于手动调用 GCval configProvider = { LeakCanary.config } // 配置项val handlerThread = HandlerThread(LEAK_CANARY_THREAD_NAME) handlerThread.start() val backgroundHandler = Handler(handlerThread.looper) // 发起内存泄漏检测的线程// 堆转存储触发器 heapDumpTrigger = HeapDumpTrigger( application, backgroundHandler, LeakSentry.refWatcher, gcTrigger, heapDumper, configProvider ) application.registerVisibilityListener { applicationVisible -> // 这里的applicationVisible其实就是调用扩展函数registerVisibilityListener // 的时候,创建的VisibilityTracker对象传入的listener变量 // 在接收生命周期回调的时候,在onActivityStarted传入true, // 在onActivityStopped传入false // 这里这里的applicationVisible在onStarted的时候是true // 在onStopped的时候是false this.applicationVisible = applicationVisible // 在applicationVisible是false的时候,其内部才会去检查 heapDumpTrigger.onApplicationVisibilityChanged(applicationVisible) } // 这是添加动态快捷方式,即在手机桌面添加一个LeakCanary的快捷方式,在debug模式下 addDynamicShortcut(application) }

// 该方法主要是用于在手机桌面动态生成LeakCanary快捷方式 private fun addDynamicShortcut(application: Application) { // 如果系统版本小于25,则不添加动态快捷方式 if (VERSION.SDK_INT < VERSION_CODES.N_MR1) { return } // 判断是否允许添加动态快捷方式 if (!application.resources.getBoolean(R.bool.leak_canary_add_dynamic_shortcut)) { return }val shortcutManager = application.getSystemService(ShortcutManager::class.java)!! val dynamicShortcuts = shortcutManager.dynamicShortcutsval shortcutInstalled = dynamicShortcuts.any { shortcut -> shortcut.id == DYNAMIC_SHORTCUT_ID }if (shortcutInstalled) { return }val mainIntent = Intent(Intent.ACTION_MAIN, null) mainIntent.addCategory(Intent.CATEGORY_LAUNCHER) mainIntent.setPackage(application.packageName) val activities = application.packageManager.queryIntentActivities(mainIntent, 0) .filter { it.activityInfo.name != "leakcanary.internal.activity.LeakLauncherActivity" }if (activities.isEmpty()) { return }val firstMainActivity = activities.first() .activityInfo// Displayed on long tap on app icon val longLabel: String // Label when dropping shortcut to launcher val shortLabel: Stringval leakActivityLabel = application.getString(R.string.leak_canary_shortcut_label)if (activities.isEmpty()) { longLabel = leakActivityLabel shortLabel = leakActivityLabel } else {val firstLauncherActivityLabel = if (firstMainActivity.labelRes != 0) { application.getString(firstMainActivity.labelRes) } else { val applicationInfo = application.applicationInfo if (applicationInfo.labelRes != 0) { application.getString(applicationInfo.labelRes) } else { applicationInfo.nonLocalizedLabel.toString() } } val fullLengthLabel = "$firstLauncherActivityLabel $leakActivityLabel" // short label should be under 10 and long label under 25 if (fullLengthLabel.length > 10) { if (fullLengthLabel.length <= 25) { longLabel = fullLengthLabel shortLabel = leakActivityLabel } else { longLabel = leakActivityLabel shortLabel = leakActivityLabel } } else { longLabel = fullLengthLabel shortLabel = fullLengthLabel } }val componentName = ComponentName(firstMainActivity.packageName, firstMainActivity.name)val shortcutCount = dynamicShortcuts.count { shortcutInfo -> shortcutInfo.activity == componentName } + shortcutManager.manifestShortcuts.count { shortcutInfo -> shortcutInfo.activity == componentName }if (shortcutCount >= shortcutManager.maxShortcutCountPerActivity) { return }val intent = leakDisplayActivityIntent intent.action = "Dummy Action because Android is stupid" val shortcut = Builder(application, DYNAMIC_SHORTCUT_ID) .setLongLabel(longLabel) .setShortLabel(shortLabel) .setActivity(componentName) .setIcon(Icon.createWithResource(application, R.mipmap.leak_canary_icon)) .setIntent(intent) .build()try { shortcutManager.addDynamicShortcuts(listOf(shortcut)) } catch (ignored: Throwable) { CanaryLog.d( ignored, "Could not add dynamic shortcut. " + "shortcutCount=$shortcutCount, " + "maxShortcutCountPerActivity=${shortcutManager.maxShortcutCountPerActivity}" ) } }

四、FragmentDestroyWatcher.install 这里使用的RefWatcher对象,是在InternalLeakSentry中进行初始化的,然后在调用ActivityDestroyWatcher和FragmentDestroyWatcher的install方法的时候,传入。
internal interface FragmentDestroyWatcher { // 实现类是SupportFragmentDestroyWatcherfun watchFragments(activity: Activity)companion object {private const val SUPPORT_FRAGMENT_CLASS_NAME = "androidx.fragment.app.Fragment"fun install( application: Application, refWatcher: RefWatcher, configProvider: () -> LeakSentry.Config ) { val fragmentDestroyWatchers = mutableListOf()if (SDK_INT >= O) { // >= 26,使用 AndroidOFragmentDestroyWatcher fragmentDestroyWatchers.add( AndroidOFragmentDestroyWatcher(refWatcher, configProvider) ) }if (classAvailable( SUPPORT_FRAGMENT_CLASS_NAME ) ) { fragmentDestroyWatchers.add( // androidx 使用 SupportFragmentDestroyWatcher SupportFragmentDestroyWatcher(refWatcher, configProvider) ) }if (fragmentDestroyWatchers.size == 0) { return }application.registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacksAdapter() { override fun onActivityCreated( activity: Activity, savedInstanceState: Bundle? ) { // 遍历所有的fragmentDestroyWatchers // 调用其watchFragments,其实就是调用SupportFragmentDestroyWatcher // 中的方法实现 // 遍历fragmentDestroyWatchers调用watchFragments的时候 // 其实就是对fragment添加生命周期监听,用于在生命周期回调的时候调用RefWatcher.watch方法 for (watcher in fragmentDestroyWatchers) { watcher.watchFragments(activity) } } }) }private fun classAvailable(className: String): Boolean { return try { Class.forName(className) true } catch (e: ClassNotFoundException) { false } } } }

internal class SupportFragmentDestroyWatcher( private val refWatcher: RefWatcher, private val configProvider: () -> Config ) : FragmentDestroyWatcher {// 这是注册给fragment的生命周期监听的 // 从这里可以看出,fragment销毁的时候,其实也会调用RefWatcher.watch private val fragmentLifecycleCallbacks = object : FragmentManager.FragmentLifecycleCallbacks() {override fun onFragmentViewDestroyed( fm: FragmentManager, fragment: Fragment ) { val view = fragment.view if (view != null && configProvider().watchFragmentViews) { refWatcher.watch(view) } }override fun onFragmentDestroyed( fm: FragmentManager, fragment: Fragment ) { if (configProvider().watchFragments) { refWatcher.watch(fragment) } } }override fun watchFragments(activity: Activity) { // 这里就是根据传入的FragmentActivity,然后获取supportFragmentManager // 对Fragment进行生命周期的监听注册 if (activity is FragmentActivity) { val supportFragmentManager = activity.supportFragmentManager supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true) } } }

五、RefWatcher 在监测Activity和Fragment的生命周期进行内存回收以及是否泄露的过程,就是调用RefWatcher.watch方法进行,该方法是使用Synchronized修饰的同步方法。RefWatcher.watch的方法,一般是在Activity和Fragment生命周期执行到onDestroy的时候调用。根据生命周期监听触发回调,然后调用RefWatcher.watch方法。
class RefWatcher constructor( private val clock: Clock, private val checkRetainedExecutor: Executor, private val onReferenceRetained: () -> Unit, /** * Calls to [watch] will be ignored when [isEnabled] returns false */ private val isEnabled: () -> Boolean = { true } ) {/** * References passed to [watch] that haven't made it to [retainedReferences] yet. * watch() 方法传进来的引用,尚未判定为泄露 */ private val watchedReferences = mutableMapOf() /** * References passed to [watch] that we have determined to be retained longer than they should * have been. * watch() 方法传进来的引用,已经被判定为泄露 */ private val retainedReferences = mutableMapOf() // 引用队列,配合弱引用使用,当弱引用中的对象被回收时,接收弱引用对象 private val queue = ReferenceQueue() val hasRetainedReferences: Boolean @Synchronized get() { removeWeaklyReachableReferences() return retainedReferences.isNotEmpty() }val hasWatchedReferences: Boolean @Synchronized get() { removeWeaklyReachableReferences() return retainedReferences.isNotEmpty() || watchedReferences.isNotEmpty() }val retainedKeys: Set @Synchronized get() { removeWeaklyReachableReferences() return HashSet(retainedReferences.keys) }/** * Identical to [.watch] with an empty string reference name. */ @Synchronized fun watch(watchedReference: Any) { watch(watchedReference, "") }/** * Watches the provided references. * * @param referenceName An logical identifier for the watched object. */ @Synchronized fun watch( watchedReference: Any, referenceName: String ) { if (!isEnabled()) { return } // 移除队列中将要被 GC 的引用 removeWeaklyReachableReferences() val key = UUID.randomUUID() .toString() val watchUptimeMillis = clock.uptimeMillis() // 构建当前引用的弱引用对象,并关联引用队列 queue // queue是一个ReferenceQueue对象,该对象是用来保存已经回收了的对象的弱引用 // 即构建给对象构建弱引用对象,当对象被回收的时候,引用该对象的弱引用就会被加入到ReferenceQueue队列的末尾 val reference = KeyedWeakReference(watchedReference, key, referenceName, watchUptimeMillis, queue) if (referenceName != "") { CanaryLog.d( "Watching instance of %s named %s with key %s", reference.className, referenceName, key ) } else { CanaryLog.d( "Watching instance of %s with key %s", reference.className, key ) } // 如果该对象尚未被判定为泄露,则将该弱引用加入到watchedReferences // 将引用存入 watchedReferences watchedReferences[key] = reference // 这里采用线程池执行 // 该线程池的赋值是在InternalLeakSentry初始化RefWatcher对象的时候赋值的 // 该线程池的内部执行是采用mainHandler的方式,切换到主线程进行执行 /* private val checkRetainedExecutor = Executor { // 默认五秒后执行 mainHandler.postDelayed(it, LeakSentry.config.watchDurationMillis) } LeakSentry.config.watchDurationMillis的定义是在LeakSentry val watchDurationMillis: Long = TimeUnit.SECONDS.toMillis(5) */ checkRetainedExecutor.execute { moveToRetained(key) // 如果当前引用未被移除,仍在 watchedReferences队列中, // 说明仍未被 GC,移入 retainedReferences 队列中,暂时标记为泄露 } }@Synchronized private fun moveToRetained(key: String) { removeWeaklyReachableReferences() // 再次调用,防止遗漏 val retainedRef = watchedReferences.remove(key) if (retainedRef != null) {//说明可能存在内存泄漏 retainedReferences[key] = retainedRef onReferenceRetained() } }@Synchronized fun removeRetainedKeys(keysToRemove: Set) { retainedReferences.keys.removeAll(keysToRemove) }@Synchronized fun clearWatchedReferences() { watchedReferences.clear() retainedReferences.clear() }private fun removeWeaklyReachableReferences() { // WeakReferences are enqueued as soon as the object to which they point to becomes weakly // reachable. This is before finalization or garbage collection has actually happened. // 弱引用一旦变得弱可达,就会立即入队。这将在 finalization 或者 GC 之前发生。 var ref: KeyedWeakReference? do { ref = queue.poll() as KeyedWeakReference? // 队列 queue 中的对象都是会被 GC 的 if (ref != null) {//说明被释放了 val removedRef = watchedReferences.remove(ref.key)//获取被释放的引用的key if (removedRef == null) { retainedReferences.remove(ref.key) } // 移除 watchedReferences 队列中的会被 GC 的 ref 对象,剩下的就是可能泄露的对象 } } while (ref != null) } }

private fun removeWeaklyReachableReferences() { // WeakReferences are enqueued as soon as the object to which they point to becomes weakly // reachable. This is before finalization or garbage collection has actually happened. // 弱引用一旦变得弱可达,就会立即入队。这将在 finalization 或者 GC 之前发生。 var ref: KeyedWeakReference? do { ref = queue.poll() as KeyedWeakReference? // 队列 queue 中的对象都是会被 GC 的 if (ref != null) { //说明queue中有弱引用对象,说明该弱引用对象引用的对象被释放了 // 获取被释放的引用的key // 从两个map集合中进行释放 val removedRef = watchedReferences.remove(ref.key) // 这里判断为空的原因是,如果在watchedReferences中没有该对象 // 那么说明该对象已经被判定为泄露,但是这个时候该对象又被回收了, // 所以得从这个判定泄露的集合中移除该判定 if (removedRef == null) { retainedReferences.remove(ref.key) } // 移除 watchedReferences 队列中的会被 GC 的 ref 对象,剩下的就是可能泄露的对象 } } while (ref != null) }

@Synchronized private fun moveToRetained(key: String) { // 再次调用,防止遗漏 removeWeaklyReachableReferences() // 如果移除ReferenceQueue队列中的弱引用之后, // 在watchedReferences队列中依然还有该对象,说明该弱引用引用的对象在此时依然不是弱可达 // 此时就不会移除watchedReferences中的弱引用 // 那么说明此时就存在内存泄露的可能,则需要将watchedReferences中key对应的弱引用 // 加入到retainedReferences中,判断该弱引用引用的对象是可能泄露的对象 val retainedRef = watchedReferences.remove(key) if (retainedRef != null) {//说明可能存在内存泄漏 retainedReferences[key] = retainedRef onReferenceRetained() } }

六、VisibilityTracker VisibilityTracker其实就是在InternalLeakCanary.onLeakSentryInstalled方法中通过调用application.registerVisibilityListener方法的时候,添加的Application.ActivityLifecycleCallbacks,这里采用适配器模式,使用适配器模式的目的,其实就是不需要重写所有方法,只在VisibilityTracker中重写需要使用的方法。
VisibilityTracker的目的其实就是监听Activity的生命周期变化,即是否是执行到了onStart和onStop,如果是onStop的时候,则做内存泄露监测工作。
VisibilityTracker与ActivityDestroyWatcher有点区别,ActivityDestroyWatcher是最终Activity执行onDestroy的时候进行内存泄露分析
internal class VisibilityTracker( private val listener: (Boolean) -> Unit ) : ActivityLifecycleCallbacksAdapter() {private var startedActivityCount = 0/** * Visible activities are any activity started but not stopped yet. An activity can be paused * yet visible: this will happen when another activity shows on top with a transparent background * and the activity behind won't get touch inputs but still need to render / animate. */ private var hasVisibleActivities: Boolean = falseoverride fun onActivityStarted(activity: Activity) { startedActivityCount++ if (!hasVisibleActivities && startedActivityCount == 1) { hasVisibleActivities = true listener.invoke(true) } }override fun onActivityStopped(activity: Activity) { // This could happen if the callbacks were registered after some activities were already // started. In that case we effectively considers those past activities as not visible. if (startedActivityCount > 0) { startedActivityCount-- } if (hasVisibleActivities && startedActivityCount == 0 && !activity.isChangingConfigurations) { hasVisibleActivities = false // 这里就是给InternalLeakCanary.onLeakSentryInstalled中注册的application.registerVisibilityListener // 传入的listener的回调传入参数为false,表示需要进行内存泄露检测 listener.invoke(false) } } }internal fun Application.registerVisibilityListener(listener: (Boolean) -> Unit) { // 当生命周期回调的时候,就会调用VisibilityTracker中重写的方法 // 而在VisibilityTracker中重写了started和stopped两个方法 // 在started中调用listener的时候传入的参数是true // 在stopped中调用listener的时候传入的参数是false // 然后在listener这个接口实现的回调中就会接收该listener的参数 // 在根据该参数判断是否需要进行内存泄露监测,这里就是回调到了 // InternalLeakCanary.onLeakSentryInstalled中注册的application.registerVisibilityListener // 进而调用到了HeapDumpTrigger.onApplicationVisibilityChanged registerActivityLifecycleCallbacks(VisibilityTracker(listener)) }

七、HeapDumpTrigger#onApplicationVisibilityChanged 本方法是在InternalLeakCanary.onLeakSentryInstalled给application添加生命周期回调的时候,根据onStart和onStop生命周期的变化来进行Heap Dump(heap dump文件(.hprof))
当生命周期执行到onStop的时候,会向该Application的扩展函数registerVisibilityListener的参数listener这个高阶函数传入boolean参数为false
看InternalLeakCanary#onLeakSentryInstalled方法中对application添加的生命周期监听,这是调用了application的扩展函数,该扩展函数是在VisibilityTracker中定义的。
application.registerVisibilityListener { applicationVisible -> this.applicationVisible = applicationVisible heapDumpTrigger.onApplicationVisibilityChanged(applicationVisible) }

其实registerVisibilityListener方法内部调用的就是application的registerActivityLifecycleCallbacks方法,传入的是Application.ActivityLifecycleCallbacks对象,这里传入的是VisibilityTracker,其实VisibilityTracker就是Application.ActivityLifecycleCallbacks的子类实现。
internal fun Application.registerVisibilityListener(listener: (Boolean) -> Unit) { registerActivityLifecycleCallbacks(VisibilityTracker(listener)) }

HeapDumpTrigger.onApplicationVisibilityChanged方法的调用,就是根据上述传给VisibilityTracker的listener函数来回调调用的,listener接收的是false的时候,就会调用scheduleRetainedInstanceCheck,接收的是false的时候是生命周期执行到onStop的时候。
fun onApplicationVisibilityChanged(applicationVisible: Boolean) { if (applicationVisible) { applicationInvisibleAt = -1L } else { applicationInvisibleAt = SystemClock.uptimeMillis() scheduleRetainedInstanceCheck("app became invisible", LeakSentry.config.watchDurationMillis) } }

这里的delayMillis默认是5s,因为该参数接收的是LeakSentry.config.watchDurationMillis,这个值初始默认值是5s。
private fun scheduleRetainedInstanceCheck( reason: String, delayMillis: Long // 默认 5 s ) { if (checkScheduled) { return } checkScheduled = true // 通过handler切换到主线程调用,确保是在主线程执行,并且延迟5S执行。 backgroundHandler.postDelayed({ checkScheduled = false checkRetainedInstances(reason) }, delayMillis) }

private fun checkRetainedInstances(reason: String) { CanaryLog.d("Checking retained instances because %s", reason) val config = configProvider() // A tick will be rescheduled when this is turned back on. if (!config.dumpHeap) { return } // RefWatcher.retainedKeys是一个Set集合,该Set集合是从 // RefWatcher.retainedReferences中获取的数据 // RefWatcher.retainedReferences存储的就是已经被判定为泄露的 var retainedKeys = refWatcher.retainedKeys// 当前泄露实例个数小于 5 个,不进行 heap dump if (checkRetainedCount(retainedKeys, config.retainedVisibleThreshold)) returnif (!config.dumpHeapWhenDebugging && DebuggerControl.isDebuggerAttached) { showRetainedCountWithDebuggerAttached(retainedKeys.size) scheduleRetainedInstanceCheck("debugger was attached", WAIT_FOR_DEBUG_MILLIS) CanaryLog.d( "Not checking for leaks while the debugger is attached, will retry in %d ms", WAIT_FOR_DEBUG_MILLIS ) return }// 可能存在被观察的引用将要变得弱可达,但是还未入队引用队列。 // 这时候应该主动调用一次 GC,可能可以避免一次 heap dump // 即被判定为内存泄露的队列中可能有些引用将要变成弱可达 // 这个时候就是将被判定为泄露的一些对象,进行再一次回收。 gcTrigger.runGc()retainedKeys = refWatcher.retainedKeysif (checkRetainedCount(retainedKeys, config.retainedVisibleThreshold)) return // 为heap dump设置被判定为内存泄露的对应的key集合 HeapDumpMemoryStore.setRetainedKeysForHeapDump(retainedKeys)CanaryLog.d("Found %d retained references, dumping the heap", retainedKeys.size) HeapDumpMemoryStore.heapDumpUptimeMillis = SystemClock.uptimeMillis() dismissNotification() // 输出一个heap dump 文件 val heapDumpFile = heapDumper.dumpHeap() // AndroidHeapDumper if (heapDumpFile == null) { CanaryLog.d("Failed to dump heap, will retry in %d ms", WAIT_AFTER_DUMP_FAILED_MILLIS) scheduleRetainedInstanceCheck("failed to dump heap", WAIT_AFTER_DUMP_FAILED_MILLIS) showRetainedCountWithHeapDumpFailed(retainedKeys.size) return }refWatcher.removeRetainedKeys(retainedKeys) // 移除已经 heap dump 的 retainedKeysHeapAnalyzerService.runAnalysis(application, heapDumpFile) // 分析 heap dump 文件 }

    推荐阅读