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 检查方法
KeyedWeakReferencewatchedObjects[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)
}
}