文章目录
- [Android LeakCanary源码分析](#Android LeakCanary源码分析)
-
- 概述
- 核心类
- 流程
- 源码分析
-
-
- MainProcessAppWatcherInstaller.onCreate()
- AppWatcher.manualInstall()
- ActivityWatcher类
- ObjectWatcher类基本属性
- ObjectWatcher.expectWeaklyReachable()
- ObjectWatcher.removeWeaklyReachableObjects()
- ObjectWatcher.moveToRetained()
- InternalLeakCanary.onObjectRetained()
- HeapDumpTrigger.scheduleRetainedObjectCheck()
- HeapDumpTrigger.checkRetainedObjects()
- HeapDumpTrigger.dumpHeap()
-
Android LeakCanary源码分析
概述
LeakCanary 2 是 Square 公司推出的用于 Android 应用自动检测内存泄漏 的开源库。
核心类
- MainProcessAppWatcherInstaller:继承自ContentProvider类,是 LeakCanary 的初始化类
- AppWatcher:全局监听器的管理入口,初始化所有的监听器
- ActivityWatcher:Activity 监控器,用于监听 Activity 的内存泄露
- ObjectWatcher:核心监听器类,全局单例,将对象包装为带 ReferenceQueue 的 WeakReference 对象,默认5秒后触发GC,检查未被回收的对象
- KeyedWeakReference:继承自 WeakReference 类,内存持有被引用对象和引用队列
流程
- 初始化:在 MainProcessAppWatcherInstaller.onCreate() 中初始化,
- MainProcessAppWatcherInstaller 是一个 ContentProvider
- ContentProvider.onCreate() 在 Application.onCreate() 之前被系统调用
- 监控对象:
- AppWatcher.manualInstall():安装4种监控器
- 例如 ActivityWatcher,在安装时会绑定生命周期,在 Activity 销毁时会回调 onDestory(),触发内存监控,这时会将 Activity 对象包装成 KeyedWeakReference 对象,并将该对象放入观察集合(watchedObjects)中
- 检测泄露:
- 每次监控对象时,会先清理已回收对象,再延迟5秒检查,将所有监控对象交给 HeapDumpTrigger 处理
- 轮询 checkRetainedObjects() 检查泄露对象,每次调用都会主动触发一次 GC
- 是否生成 dump 为年,前台状态,>= 5个泄露对象才生成,后台状态,>=1个立即生成
- 生成内存快照:最终调用
Debug.dumpHprofData(heapDumpFile.absolutePath)生成内存快照 - 分析泄露:使用 Shark 分析内存快照
源码分析
MainProcessAppWatcherInstaller.onCreate()
xml
<application>
<provider
android:name="leakcanary.internal.MainProcessAppWatcherInstaller"
android:authorities="${applicationId}.leakcanary-installer"
android:enabled="@bool/leak_canary_watcher_auto_install"
android:exported="false" />
</application>
kotlin
internal class MainProcessAppWatcherInstaller : ContentProvider() {
override fun onCreate(): Boolean {
val application = context!!.applicationContext as Application
// 安装监控器
AppWatcher.manualInstall(application)
return true
}
}
MainProcessAppWatcherInstaller 类是继承自 ContentProvider。
App 在启动时,系统会在 Application.onCreate() 之前调用所有注册的 ContentProvider.onCreate()。
接着调用 AppWatcher.manualInstall() 自动安装各种监听器。
AppWatcher.manualInstall()
kotlin
@JvmOverloads
fun manualInstall(
application: Application,
retainedDelayMillis: Long = TimeUnit.SECONDS.toMillis(5), // 延迟5秒执行
watchersToInstall: List<InstallableWatcher> = appDefaultWatchers(application) // 安装所有监控器
) {
// 检查主线程
checkMainThread()
// 防止重复安装
if (isInstalled) {
throw IllegalStateException(
"AppWatcher already installed, see exception cause for prior install call", installCause
)
}
this.retainedDelayMillis = retainedDelayMillis
if (application.isDebuggableBuild) {
LogcatSharkLog.install()
}
// 会反射调用InternalLeakCanary
LeakCanaryDelegate.loadLeakCanary(application)
// 安装所有的内存监听器
watchersToInstall.forEach {
it.install()
}
// Only install after we're fully done with init.
installCause = RuntimeException("manualInstall() first called here")
}
// 创建所有监听器
fun appDefaultWatchers(
application: Application,
reachabilityWatcher: ReachabilityWatcher = objectWatcher //
): List<InstallableWatcher> {
return listOf(
ActivityWatcher(application, reachabilityWatcher),
FragmentAndViewModelWatcher(application, reachabilityWatcher),
RootViewWatcher(reachabilityWatcher),
ServiceWatcher(reachabilityWatcher)
)
}
// 全局单例,用于观察对象
val objectWatcher = ObjectWatcher(
clock = { SystemClock.uptimeMillis() },
checkRetainedExecutor = {
check(isInstalled) {
"AppWatcher not installed"
}
mainHandler.postDelayed(it, retainedDelayMillis)
},
isEnabled = { true }
)
ActivityWatcher类
kotlin
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也就是ObjectWather
// 在Activity.onDestroy()时,观察该对象
reachabilityWatcher.expectWeaklyReachable(
activity, "${activity::class.java.name} received Activity#onDestroy() callback"
)
}
}
// 安装
override fun install() {
// 监听生命周期
application.registerActivityLifecycleCallbacks(lifecycleCallbacks)
}
override fun uninstall() {
application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks)
}
}
ObjectWatcher类基本属性
kotlin
class ObjectWatcher {
// 后台调度器
private val checkRetainedExecutor: Executor
// watchedObjects是Map集合,用于存放监控对象
// 监控对象是KeyedWeakReference类型,是弱引用的包装类,内部持有监控对象和回收队列
private val watchedObjects = mutableMapOf<String, KeyedWeakReference>()
// 被GC回收的弱引用
private val queue = ReferenceQueue<Any>()
// 泄露对象数量
val retainedObjectCount: Int
@Synchronized get() {
removeWeaklyReachableObjects()
return watchedObjects.count { it.value.retainedUptimeMillis != -1L }
}
}
ObjectWatcher.expectWeaklyReachable()
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)
// 放入观察集合
watchedObjects[key] = reference
// 延迟5s后执行
checkRetainedExecutor.execute {
moveToRetained(key)
}
}
ObjectWatcher.removeWeaklyReachableObjects()
kotlin
// 清理已回收的对象
private fun removeWeaklyReachableObjects() {
var ref: KeyedWeakReference?
do {
ref = queue.poll() as KeyedWeakReference?
if (ref != null) {
// 从观察集合中移除已回收对象
watchedObjects.remove(ref.key)
}
} while (ref != null)
}
ObjectWatcher.moveToRetained()
kotlin
@Synchronized private fun moveToRetained(key: String) {
// 先清理已回收对象
removeWeaklyReachableObjects()
val retainedRef = watchedObjects[key]
if (retainedRef != null) {
retainedRef.retainedUptimeMillis = clock.uptimeMillis()
// 回调通知LeakCanary处理,最终交给InternalLeakCanary.onObjectRetained()处理
onObjectRetainedListeners.forEach { it.onObjectRetained() }
}
}
InternalLeakCanary.onObjectRetained()
kotlin
override fun onObjectRetained() = scheduleRetainedObjectCheck()
fun scheduleRetainedObjectCheck() {
if (this::heapDumpTrigger.isInitialized) {
heapDumpTrigger.scheduleRetainedObjectCheck()
}
}
HeapDumpTrigger.scheduleRetainedObjectCheck()
kotlin
// 检查泄露对象
fun scheduleRetainedObjectCheck(
delayMillis: Long = 0L
) {
val checkCurrentlyScheduledAt = checkScheduledAt
if (checkCurrentlyScheduledAt > 0) {
return
}
checkScheduledAt = SystemClock.uptimeMillis() + delayMillis
backgroundHandler.postDelayed({
checkScheduledAt = 0
checkRetainedObjects()
}, delayMillis)
}
HeapDumpTrigger.checkRetainedObjects()
kotlin
// 检查泄露对象
private fun checkRetainedObjects() {
// 统计泄露对象数量
var retainedReferenceCount = objectWatcher.retainedObjectCount
if (retainedReferenceCount > 0) {
// 主动触发GC,并等待100ms
gcTrigger.runGc()
// 重新获取泄漏对象计数
retainedReferenceCount = objectWatcher.retainedObjectCount
}
// 检查泄露对象
// 前台状态:阈值为5,小于阈值不dump
// 后台状态:只要有泄露对象立即dump
if (checkRetainedCount(retainedReferenceCount, config.retainedVisibleThreshold)) return
dismissRetainedCountNotification()
val visibility = if (applicationVisible) "visible" else "not visible"
// 触发dumpHeap
dumpHeap(
retainedReferenceCount = retainedReferenceCount,
retry = true,
reason = "$retainedReferenceCount retained objects, app is $visibility"
)
}
HeapDumpTrigger.dumpHeap()
kotlin
private fun dumpHeap(
retainedReferenceCount: Int,
retry: Boolean,
reason: String
) {
// dump的存储文件
val directoryProvider = InternalLeakCanary.createLeakDirectoryProvider(InternalLeakCanary.application)
val heapDumpFile = directoryProvider.newHeapDumpFile()
val durationMillis: Long
if (currentEventUniqueId == null) {
currentEventUniqueId = UUID.randomUUID().toString()
}
try {
InternalLeakCanary.sendEvent(DumpingHeap(currentEventUniqueId!!))
if (heapDumpFile == null) {
throw RuntimeException("Could not create heap dump file")
}
saveResourceIdNamesToMemory()
val heapDumpUptimeMillis = SystemClock.uptimeMillis()
KeyedWeakReference.heapDumpUptimeMillis = heapDumpUptimeMillis
durationMillis = measureDurationMillis {
// 最终调用 Debug.dumpHprofData(heapDumpFile.absolutePath),堆转储过程(内存快照)
configProvider().heapDumper.dumpHeap(heapDumpFile)
}
if (heapDumpFile.length() == 0L) {
throw RuntimeException("Dumped heap file is 0 byte length")
}
lastDisplayedRetainedObjectCount = 0
lastHeapDumpUptimeMillis = SystemClock.uptimeMillis()
objectWatcher.clearObjectsWatchedBefore(heapDumpUptimeMillis)
currentEventUniqueId = UUID.randomUUID().toString()
InternalLeakCanary.sendEvent(HeapDump(currentEventUniqueId!!, heapDumpFile, durationMillis, reason))
} catch (throwable: Throwable) {
}
}