最近结合网上的文章看了下LeakCanary的代码,了解原理之后,顿时出现了我上我也行
的感觉,对此记录一下。
实现思路
leakcanary主要是监控activity和fragment的内存泄露,这里先说下leakcanary的实现思路,
- 监控activity和fragment的生命周期,搭配Reference引用,判断是否被回收;
- 在确定内存泄露之后,获取内存快照,分析具体内存泄露的对象引用链;
本文主要是分析第一点,对于获取内存快照和分析就不在本文阐述。
先大致分析下,如何实现activity和fragment对象的内存泄露监控:
- 使用Application.registerActivityLifecycleCallbacks(callback)注册activity的生命周期监听,Fragment则使用Activity.FragmentManager.registerFragmentLifecycleCallbacks(callback);
- 在onDestroy时,使用Reference关联引用;
- 等待一段时间(默认5s),在手动GC后判断对象是否被回收。
源码解析
leakcanary版本为 com.squareup.leakcanary:leakcanary-android:2.3
先找下初始化的入口函数
在AndroidManifest.xml中,注册了contentProvider
<application>
<provider
android:name="leakcanary.internal.AppWatcherInstaller$MainProcess"
android:authorities="${applicationId}.leakcanary-installer"
android:exported="false" />
</application>
复制代码
看下leakcanary.internal.AppWatcherInstaller$MainProcess
这个类的onCreate()方法,这个方法会在Application的onCreate()之前执行。
internal sealed class AppWatcherInstaller : ContentProvider() {
//这里MainProcess实现了AppWatcherInstaller,啥都没改,直接看AppWatcherInstaller的onCreate()方法
internal class MainProcess : AppWatcherInstaller()
override fun onCreate(): Boolean {
val application = context!!.applicationContext as Application
InternalAppWatcher.install(application) //? 1
return true
}
}
复制代码
这里就是LeakCanary的初始化入口了,看下标记1
处的InternalAppWatcher.install(application)
internal object InternalAppWatcher {
fun install(application: Application) {
...
//注入Activity destroy的监听
ActivityDestroyWatcher.install(application, objectWatcher, configProvider) //? 2
//注入Fragment destroy的监听
FragmentDestroyWatcher.install(application, objectWatcher, configProvider) //? 3
onAppWatcherInstalled(application) //? 4
}
}
复制代码
标记2
、3
处,就是前面提到的,注册Activity和Fragment的onDestroy监听,两个类差不多,我就只贴一个
internal class ActivityDestroyWatcher private constructor(
private val objectWatcher: ObjectWatcher,
private val configProvider: () -> Config
) {
companion object {
fun install(
application: Application,
objectWatcher: ObjectWatcher,
configProvider: () -> Config
) {
val activityDestroyWatcher =
ActivityDestroyWatcher(objectWatcher, configProvider)
//调用Application的registerActivityLifecycleCallbacks方法注册Activity的生命周期监听
application.registerActivityLifecycleCallbacks(activityDestroyWatcher.lifecycleCallbacks) //? 5
}
}
//Activity的onDestroy方法调用后,会回调到此处
private val lifecycleCallbacks =
object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
override fun onActivityDestroyed(activity: Activity) {
if (configProvider().watchActivities) {
//把处于destroy的Activity传递给ObjectWatcher#watch
objectWatcher.watch(
activity, "${activity::class.java.name} received Activity#onDestroy() callback"
) //? 6
}
}
}
}
复制代码
标记5
处,使用application注入Activity的生命周期监听,注入的监听对象在onActivityDestroyed方法被调用时执行objectWatcher.watch()
方法,传入activity,也就是标记6
处
这个objectWatcher
对象是在调用install
时传入的参数,需要回到InternalAppWatcher
类的install
方法看下objectWatcher
的初始化
回头(过程省略)在InternalAppWatcher
类中发现,objectWatcher是它的成员变量,是ObjectWatcher
类的实例
那么接下来就需要看下ObjectWatcher
类的watch
方法
class ObjectWatcher(...){
@Synchronized fun watch(
watchedObject: Any, description: String
) {
//将已回收的观察对象引用移除掉
removeWeaklyReachableObjects() //? 7
val key = UUID.randomUUID().toString()
val watchUptimeMillis = clock.uptimeMillis()
//KeyedWeakReference是拓展了WeakReference类,添加了一些变量,如开始监听时间、类的描述、关联的Key等等
//这里的queue需要注意,它是ReferenceQueue类,与WeakReference关联后,若对象被回收,WeakReference就会被添加到queue中
val reference = KeyedWeakReference(watchedObject, key, description, watchUptimeMillis, queue)
//watchedObjects是Map<String, KeyedWeakReference>结构,用来缓存所有的监听对象中对象,
//如果发现已经被回收(即在queue中出现),则会根据key来移除当前对象的缓存。具体移除逻辑看removeWeaklyReachableObjects()方法
watchedObjects[key] = reference
checkRetainedExecutor.execute {
//这里是做一个延时(默认5秒),实际调用的是Handler.postDelayed(Runnable, delayMillis)
//延时后观察对象是否被回收,如果没有被回收,就会手动调用gc,gc若还有未被回收的对象,那么可以判定这个对象内存泄露
moveToRetained(key) //? 8
}
}
}
复制代码
先看下标记7
处的removeWeaklyReachableObjects()
是怎么移除已回收的对象引用
private fun removeWeaklyReachableObjects() {
var ref: KeyedWeakReference?
do {
//遍历queue,如果不为空,那么说明有观察对象被回收
ref = queue.poll() as KeyedWeakReference?
if (ref != null) {
//根据key移除缓存中的观察对象引用
watchedObjects.remove(ref.key)
}
} while (ref != null)
}
复制代码
不明白WeakReference和ReferenceQueue的可以查看我的另一篇文章[Reference和ReferenceQueue的联动效果]
接着看前面标记8
处的moveToRetained(key)
方法
@Synchronized private fun moveToRetained(key: String) {
//同样,先将已回收的观察对象移除掉
removeWeaklyReachableObjects()
val retainedRef = watchedObjects[key]
if (retainedRef != null) {
//记录观察对象被保留的时间,默认是-1,后面需要根据此处的赋值判断是否属于内存泄露
retainedRef.retainedUptimeMillis = clock.uptimeMillis() //? 9
onObjectRetainedListeners.forEach { it.onObjectRetained() } //? 10
}
}
复制代码
这里补充下标记10
处的onObjectRetainedListeners
,是通过ObjectWatcher
类的addOnObjectRetainedListener()
方法添加的
//前面标记1处调用InternalAppWatcher.install(..)时,
internal object InternalAppWatcher {
private val onAppWatcherInstalled: (Application) -> Unit
init {
//反射获取了"leakcanary.internal.InternalLeakCanary"的"INSTANCE"属性
//这里InternalLeakCanary类是用object修饰的,是个单例类,那么INSTANCE也就是InternalLeakCanary的实例
val internalLeakCanary = try {
val leakCanaryListener = Class.forName("leakcanary.internal.InternalLeakCanary")
leakCanaryListener.getDeclaredField("INSTANCE")
.get(null)
} catch (ignored: Throwable) {
NoLeakCanary
}
@kotlin.Suppress("UNCHECKED_CAST")
onAppWatcherInstalled = internalLeakCanary as (Application) -> Unit
}
fun install(application: Application) {
...
//声明的类型是一个(Application) -> Unit函数,而InternalLeakCanary实现了这个函数,
//最终调用InternalLeakCanary类的invoke(application: Application)方法
onAppWatcherInstalled(application)
}
}
internal object InternalLeakCanary : (Application) -> Unit, OnObjectRetainedListener{
override fun invoke(application: Application) {
...
//前面标记10处的onObjectRetainedListeners在此处注入
AppWatcher.objectWatcher.addOnObjectRetainedListener(this)
...
}
}
复制代码
接着看标记10
处onObjectRetainedListeners.forEach { it.onObjectRetained() }
也就是InternalLeakCanary
的onObjectRetained()
方法
internal object InternalLeakCanary : (Application) -> Unit, OnObjectRetainedListener{
override fun onObjectRetained() {
if (this::heapDumpTrigger.isInitialized) {
heapDumpTrigger.onObjectRetained()
}
}
//在invoke(application)中初始化
var heapDumpTrigger = HeapDumpTrigger(
application, backgroundHandler, AppWatcher.objectWatcher, gcTrigger, heapDumper,
configProvider
)
}
复制代码
继续看HeapDumpTrigger
的onObjectRetained()
internal class HeapDumpTrigger(..){
fun onObjectRetained() {
scheduleRetainedObjectCheck(
reason = "found new object retained",
rescheduling = false
)
private fun scheduleRetainedObjectCheck(
reason: String,
rescheduling: Boolean,
delayMillis: Long = 0L
) {
...
//子线程中执行检查和gc操作
backgroundHandler.postDelayed({
checkRetainedObjects(reason)
}, delayMillis)
}
private fun checkRetainedObjects(reason: String) {
...
//未回收的观察对象 且 保留时间不等于-1 (标记9处赋值的保留时间)
var retainedReferenceCount = objectWatcher.retainedObjectCount
if (retainedReferenceCount > 0) {
//手动GC
gcTrigger.runGc()
retainedReferenceCount = objectWatcher.retainedObjectCount
}
//如果处于观察期未回收的对象数量 小于 配置可容许的观察数,
if (checkRetainedCount(retainedReferenceCount, config.retainedVisibleThreshold)) return
//处于debug的断点状态时,可能会导致线程阻塞,需要暂时延迟执行这种情况导致的未及时回收
if (!config.dumpHeapWhenDebugging && DebuggerControl.isDebuggerAttached) {
onRetainInstanceListener.onEvent(DebuggerIsAttached)
showRetainedCountNotification(
objectCount = retainedReferenceCount,
contentText = application.getString(
R.string.leak_canary_notification_retained_debugger_attached
)
)
//debug状态下延迟检查
scheduleRetainedObjectCheck(
reason = "debugger is attached",
rescheduling = true,
delayMillis = WAIT_FOR_DEBUG_MILLIS
)
return
}
...
//确定有对象内存泄露,获取内存快照并分析内存泄露引用链
dumpHeap(retainedReferenceCount, retry = true)
}
}
复制代码
看到这里,对象的内存泄露监控逻辑就走完了。