LeakCanary源码分析
LeakCanary作为常用的内存泄漏分析工具,那是如何检测内存泄漏的呢?从注册入口分析,最新的LeakCanary 2.14
,通过ContentProvider
自动获取Context
完成注册。
xml
<provider
android: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
:
kotlin
internal class MainProcessAppWatcherInstaller : ContentProvider() {
override fun onCreate(): Boolean {
val application = context!!.applicationContext as Application
AppWatcher.manualInstall(application)
return true
}
...
}
二、AppWatcher.manualInstall
manualInstall
中 完成 安装:
kotlin
// leakcanary.internal.InternalLeakCanary 内部实现
LeakCanaryDelegate.loadLeakCanary(application)
// 相关 Activity/Fragment 组件的 检测类,都初始化
watchersToInstall.forEach {
it.install()
}
2.1 appDefaultWatchers
watchersToInstall
默认由AppWatcher.appDefaultWatchers
创建 组件的内存检查对象。他们都实现
InstallableWatcher
接口,实现install()
和uninstall()
方法。
kotlin
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 创建默认值
kotlin
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]
kotlin
@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] = reference
checkRetainedExecutor.execute {
moveToRetained(key)
}
}
相关字段说明:
KeyedWeakReference
继承自WeakReference
,增加了key
用于判断。watchedObjects
保存UUID
为key
的弱引用对象queue
为ReferenceQueue
, 用于GC回收时,弱引用会自动进入队列,也就是 未泄漏。checkRetainedExecutor
是Executor
,默认实现 延迟5s 执行。
3.3 removeWeaklyReachableObjects
queue
中是 准备被回收的Reference
。循环
queue.poll()
获取,并移除 要回收 的引用对象。
kotlin
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()
,进一步 处理。
kotlin
@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()
方法,对应:
kotlin
LeakCanaryDelegate.loadLeakCanary(application)
会通过反射 创建 InternalLeakCanary
对象, 并执行 InternalLeakCanary.invoke
方法,注册了上面的OnObjectRetainedListener
监听器:
kotlin
AppWatcher.objectWatcher.addOnObjectRetainedListener(this)
4.1 onObjectRetained
--> scheduleRetainedObjectCheck()
--> heapDumpTrigger.scheduleRetainedObjectCheck()
--> heapDumpTrigger.checkRetainedObjects()
checkRetainedObjects()
源码:
kotlin
...
var retainedReferenceCount = objectWatcher.retainedObjectCount
if (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()
4.2 GcTrigger
通过 Runtime.getRuntime().gc()
进行 GC 操作。
kotlin
object Default : GcTrigger {
override fun runGc() {
Runtime.getRuntime()
.gc()
enqueueReferences()
System.runFinalization()
}
...
}
源码:GcTrigger.kt
4.3 AndroidDebugHeapDumper
利用 Android Api Debug.dumpHprofData(path)
获取栈信息:
kotlin
object AndroidDebugHeapDumper : HeapDumper {
override fun dumpHeap(heapDumpFile: File) {
Debug.dumpHprofData(heapDumpFile.absolutePath)
}
}