源码阅读 LeakCanary
LeakCanary源码分析
LeakCanary作为常用的内存泄漏分析工具,那是如何检测内存泄漏的呢?从注册入口分析,最新的LeakCanary 2.14
,通过ContentProvider
自动获取Context
完成注册。
<providerandroid:name="leakcanary.internal.MainProcessAppWatcherInstaller"android:authorities="${applicationId}.leakcanary-installer"android:enabled="@bool/leak_canary_watcher_auto_install"android:exported="false" />
一、MainProcessAppWatcherInstaller
leakcanary.internal.MainProcessAppWatcherInstaller
的 onCreate
:
internal class MainProcessAppWatcherInstaller : ContentProvider() {override fun onCreate(): Boolean {val application = context!!.applicationContext as ApplicationAppWatcher.manualInstall(application)return true}...
}
二、AppWatcher.manualInstall
manualInstall
中 完成 安装:
// leakcanary.internal.InternalLeakCanary 内部实现
LeakCanaryDelegate.loadLeakCanary(application)// 相关 Activity/Fragment 组件的 检测类,都初始化
watchersToInstall.forEach {it.install()
}
2.1 appDefaultWatchers
watchersToInstall
默认由AppWatcher.appDefaultWatchers
创建 组件的内存检查对象。
他们都实现InstallableWatcher
接口,实现install()
和uninstall()
方法。
fun appDefaultWatchers(application: Application,reachabilityWatcher: ReachabilityWatcher = objectWatcher): List<InstallableWatcher> {return listOf(ActivityWatcher(application, reachabilityWatcher),FragmentAndViewModelWatcher(application, reachabilityWatcher),RootViewWatcher(reachabilityWatcher),ServiceWatcher(reachabilityWatcher))}
2.2 ActivityWatcher - Activity的泄漏分析
Activity
利用生命周期函数 检测。
- 利用
Application.registerActivityLifecycleCallbacks()
监听 onActivityDestroyed()
时,调用objectWatcher.expectWeaklyReachable()
进行 弱可达性分析。
三、ObjectWatcher
ObjectWatcher 完成 内存检查对象的 弱引用创建 和 GC处理。
所有 Activity Fragment View 检测的InstallableWatcher
都有objectWatcher
成员,
需要检查泄漏时,来调用expectWeaklyReachable
方法。
3.1 AppWatcher.objectWatcher 创建默认值
val objectWatcher = ObjectWatcher(clock = { SystemClock.uptimeMillis() },checkRetainedExecutor = {check(isInstalled) {"AppWatcher not installed"}mainHandler.postDelayed(it, retainedDelayMillis)},isEnabled = { true })
解释: checkRetainedExecutor
作为 Executor
实现,延迟 5s 在 mainHandler
主线程完成。
3.2 expectWeaklyReachable 检查方法
KeyedWeakReference
watchedObjects[key]
@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)SharkLog.d {"Watching " +(if (watchedObject is Class<*>) watchedObject.toString() else "instance of ${watchedObject.javaClass.name}") +(if (description.isNotEmpty()) " ($description)" else "") +" with key $key"}watchedObjects[key] = referencecheckRetainedExecutor.execute {moveToRetained(key)}}
相关字段说明:
KeyedWeakReference
继承自WeakReference
,增加了key
用于判断。watchedObjects
保存UUID
为key
的弱引用对象queue
为ReferenceQueue
, 用于GC回收时,弱引用会自动进入队列,也就是 未泄漏。checkRetainedExecutor
是Executor
,默认实现 延迟5s 执行。
3.3 removeWeaklyReachableObjects
queue
中是 准备被回收的Reference
。
循环queue.poll()
获取,并移除 要回收 的引用对象。
private fun removeWeaklyReachableObjects() {var ref: KeyedWeakReference?do {ref = queue.poll() as KeyedWeakReference?if (ref != null) {watchedObjects.remove(ref.key)}} while (ref != null)}
3.4 moveToRetained
这里会 触发
InternalLeakCanary
的onObjectRetainer()
,进一步 处理。
@Synchronized private fun moveToRetained(key: String) {removeWeaklyReachableObjects()val retainedRef = watchedObjects[key]if (retainedRef != null) {retainedRef.retainedUptimeMillis = clock.uptimeMillis()onObjectRetainedListeners.forEach { it.onObjectRetained() }}}
四、InternalLeakCanary
回到 AppWatcher.manualInstall()
方法,对应:
LeakCanaryDelegate.loadLeakCanary(application)
会通过反射 创建 InternalLeakCanary
对象, 并执行 InternalLeakCanary.invoke
方法,注册了上面的OnObjectRetainedListener
监听器:
AppWatcher.objectWatcher.addOnObjectRetainedListener(this)
4.1 onObjectRetained
–> scheduleRetainedObjectCheck()
–> heapDumpTrigger.scheduleRetainedObjectCheck()
–> heapDumpTrigger.checkRetainedObjects()
checkRetainedObjects()
源码:
...var retainedReferenceCount = objectWatcher.retainedObjectCountif (retainedReferenceCount > 0) {gcTrigger.runGc()retainedReferenceCount = objectWatcher.retainedObjectCount}...dumpHeap(retainedReferenceCount = retainedReferenceCount,retry = true,reason = "$retainedReferenceCount retained objects, app is $visibility")
这里关键地方:
gcTrigger.runGc()
运行GC,检测泄漏对象数量。heapDump()
方法,保存栈信息,本质是 Android的Debug.dumpHprofData()
看源码:HeapDumpTrigger.kt
4.2 GcTrigger
通过 Runtime.getRuntime().gc()
进行 GC 操作。
object Default : GcTrigger {override fun runGc() {Runtime.getRuntime().gc()enqueueReferences()System.runFinalization()}...}
源码:GcTrigger.kt
4.3 AndroidDebugHeapDumper
利用 Android Api Debug.dumpHprofData(path)
获取栈信息:
object AndroidDebugHeapDumper : HeapDumper {override fun dumpHeap(heapDumpFile: File) {Debug.dumpHprofData(heapDumpFile.absolutePath)}
}
文档
- LeakCanary v2.14 | Github
- LeakCanary Getting Started
- 探索Android开源框架 - 7. LeakCanary使用及源码解析
- LeakCanary2.6抽丝剥茧-源码分析
- LeakCanary2源码解析