LeakCanary源码详解

本文基于LeakCanary 2.12进行分析。

ApplicationActivityLifecycleCallbacksReachabilityWatcherObjectWatcherwatchedObjects : Map<String, KeyedWeakReference>queue : ReferenceQueue<Any>KeyedWeakReferenceWeakReferenceInstallableWatcherActivityWatcherFragmentAndViewModelWatcherRootViewWatcherServiceWatcherAppWatcher1n1n

初始化

引入LeakCanary时,只需要引入maven库的坐标即可,如下:

1
2
3
4
dependencies {
// debugImplementation because LeakCanary should only run in debug builds.
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.12'
}

而不需要进行任何的代码改动就可以使用LeakCanary了。另外,引入leakcanary时使用的是debugImplementation表示只在debug版本中才会集成leakcanary,release版本不会集成。

那么,leakcanary如何完成初始化呢?

leakcanary使用了ContentProvider来进行初始化,当app启动时系统会自动初始化注册的ContentProvider。

1
2
3
4
5
6
7
<application>
<provider
android:name="leakcanary.internal.MainProcessAppWatcherInstaller"
android:authorities="${applicationId}.leakcanary-installer"
android:enabled="@bool/leak_canary_watcher_auto_install"
android:exported="false"/>
</application>
1
2
3
4
5
6
7
8
internal class MainProcessAppWatcherInstaller : ContentProvider() {

override fun onCreate(): Boolean {
val application = context!!.applicationContext as Application
AppWatcher.manualInstall(application)
return true
}
......

系统初始化ContentProvider的时机在Application之前,即ContentProvider#onCreate先于Application#onCreate来执行,但此时Application的实例已经存在了。

注册内存泄漏监视器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
fun manualInstall(
application: Application,
retainedDelayMillis: Long = TimeUnit.SECONDS.toMillis(5),
watchersToInstall: List<InstallableWatcher> = appDefaultWatchers(application)
) {
checkMainThread()
if (isInstalled) {
throw IllegalStateException(
"AppWatcher already installed, see exception cause for prior install call", installCause
)
}
check(retainedDelayMillis >= 0) {
"retainedDelayMillis $retainedDelayMillis must be at least 0 ms"
}
this.retainedDelayMillis = retainedDelayMillis
if (application.isDebuggableBuild) {
LogcatSharkLog.install()
}
// Requires AppWatcher.objectWatcher to be set
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), //Activity内存泄漏监视器
FragmentAndViewModelWatcher(application, reachabilityWatcher), //Fragment和ViewModel内存泄漏监视器
RootViewWatcher(reachabilityWatcher), //RootView内存泄漏监视器
ServiceWatcher(reachabilityWatcher) //服务内存泄漏监视器
)
}

Activity泄漏监视

Activity的内存泄漏通过ActivityWatcher来监控。下图是Activity泄漏监控相关类图结构:

ReachabilityWatcherActivityWatcherObjectWatcherKeyedWeakReferenceOnObjectRetainedListeneronObjectRetained()«Singleton»InternalLeakCanaryvoid sendEvent(Event)HeapDumpTriggerEventListeneronEvent()«Singleton»BackgroundThreadHeapAnalyzer«Singleton»LogcatEventListener«Singleton»ToastEventListener«Singleton»AndroidDebugHeapAnalyzer1n1n
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class ActivityWatcher(
private val application: Application,
private val reachabilityWatcher: ReachabilityWatcher //ObjectWatcher实例
) : InstallableWatcher {

private val lifecycleCallbacks = //activity生命周期监听事件回调
object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
//当Activity被销毁时会收到onActivityDestroyed事件通知,其中activity参数就是被销毁的activity实例
override fun onActivityDestroyed(activity: Activity) {
reachabilityWatcher.expectWeaklyReachable(
activity, "${activity::class.java.name} received Activity#onDestroy() callback"
)
}
}

//初始化时调用,注册Activity生命周期回调监听
override fun install() {
application.registerActivityLifecycleCallbacks(lifecycleCallbacks)
}

override fun uninstall() {
application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks)
}
}

ActivityWatcher的作用是注册Activity生命周期监听,在onActivityDestroyed时将activity实例通过ObjectWatcher#expectWeaklyReachable注册到监控表中。下面看下ObjectWatcher#expectWeaklyReachable的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private val watchedObjects = mutableMapOf<String, KeyedWeakReference>()

@Synchronized override fun expectWeaklyReachable(
watchedObject: Any,
description: String
) {
if (!isEnabled()) {
return
}
removeWeaklyReachableObjects()
val key = UUID.randomUUID().toString()
val watchUptimeMillis = clock.uptimeMillis()
//KeyedWeakReference是弱引用,是WeakReference的子类
val reference = KeyedWeakReference(watchedObject, key, description, watchUptimeMillis, queue)
......
watchedObjects[key] = reference //存入监控表中
checkRetainedExecutor.execute {
moveToRetained(key) //弱引用标记为retained状态(既没有被回收)
}
}

通过一个弱引用KeyedWeakReference来持有activity,然后注册到监控表中。KeyedWeakReference构造函数指定了ReferenceQueue,因此当实例被回收后,弱引用就会被添加到ReferenceQueue中。

最后通过checkRetainedExecutor来执行一个Runnable任务,checkRetainedExecutor在ObjectWatcher的构造函数中传入,定义如下:

1
2
3
4
5
6
7
8
9
10
11
val objectWatcher = ObjectWatcher(
clock = { SystemClock.uptimeMillis() },
checkRetainedExecutor = {
check(isInstalled) {
"AppWatcher not installed"
}
//在主线程执行一个延时任务,retainedDelayMillis默认值是5秒
mainHandler.postDelayed(it, retainedDelayMillis)
},
isEnabled = { true }
)

总结一下上面的代码流程:当activity被销毁后,会创建一个弱引用KeyedWeakReference来持有这个activity实例,KeyedWeakReference还包含了一个uuid和activity的描述信息,而且弱引用关联了ReferenceQueue,在对象实例被回收后,弱引用本身会被添加到ReferenceQueue中。然后启动一个延时5秒(可配置)的任务来检查这个弱引用持有的实例是否被回收。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//引用队列,当弱引用持有的实例被回收后,弱引用本身会被添加到队列中
private val queue = ReferenceQueue<Any>()

@Synchronized private fun moveToRetained(key: String) {
removeWeaklyReachableObjects() //清理已经被GC回收的对象弱引用
val retainedRef = watchedObjects[key]
if (retainedRef != null) { //不为空表示key对应的监控对象(activity)没有被回收,可能存在内存泄漏
retainedRef.retainedUptimeMillis = clock.uptimeMillis() //更新retained时间
//onObjectRetainedListeners是一个监听者列表,InternalLeakCanary就是其中之一,默认也是唯一的一个
onObjectRetainedListeners.forEach { it.onObjectRetained() }
}
}

private fun removeWeaklyReachableObjects() {
// WeakReferences are enqueued as soon as the object to which they point to becomes weakly
// reachable. This is before finalization or garbage collection has actually happened.
var ref: KeyedWeakReference?
do {
ref = queue.poll() as KeyedWeakReference?
if (ref != null) {
//从引用队列中拿到的对象就表示这个实例已经被GC正常回收了,所以从监控表中删除引用
watchedObjects.remove(ref.key)
}
} while (ref != null)
}

当检测到对象没有被回收后,会调用leakcanary.internal.InternalLeakCanary#onObjectRetained来触发泄漏检测:

1
2
3
4
5
6
7
8
//InternalLeakCanary.kt
override fun onObjectRetained() = scheduleRetainedObjectCheck()

fun scheduleRetainedObjectCheck() {
if (this::heapDumpTrigger.isInitialized) {
heapDumpTrigger.scheduleRetainedObjectCheck()
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
//HeapDumpTrigger.kt
fun scheduleRetainedObjectCheck(
delayMillis: Long = 0L //默认延时是0,调用时没有传参,所以使用默认值0
) {
val checkCurrentlyScheduledAt = checkScheduledAt
if (checkCurrentlyScheduledAt > 0) {
return
}
checkScheduledAt = SystemClock.uptimeMillis() + delayMillis
backgroundHandler.postDelayed({ //启动后台任务
checkScheduledAt = 0
checkRetainedObjects()
}, delayMillis)
}

//检测内存泄漏
private fun checkRetainedObjects() {
......//忽略部分代码

//获取泄漏对象个数
var retainedReferenceCount = objectWatcher.retainedObjectCount

if (retainedReferenceCount > 0) {
gcTrigger.runGc() //执行Runtime.getRuntime().gc()
retainedReferenceCount = objectWatcher.retainedObjectCount
}

//检查对象泄漏个数,如果小于阈值(默认是5)直接返回不执行后续步骤
if (checkRetainedCount(retainedReferenceCount, config.retainedVisibleThreshold)) return

val now = SystemClock.uptimeMillis()
val elapsedSinceLastDumpMillis = now - lastHeapDumpUptimeMillis
//如果距离上次分析堆栈信息不足1分钟则返回
if (elapsedSinceLastDumpMillis < WAIT_BETWEEN_HEAP_DUMPS_MILLIS) {
onRetainInstanceListener.onEvent(DumpHappenedRecently)
showRetainedCountNotification(
objectCount = retainedReferenceCount,
contentText = application.getString(R.string.leak_canary_notification_retained_dump_wait)
)
scheduleRetainedObjectCheck(
delayMillis = WAIT_BETWEEN_HEAP_DUMPS_MILLIS - elapsedSinceLastDumpMillis
)
return
}

dismissRetainedCountNotification()
val visibility = if (applicationVisible) "visible" else "not visible"
dumpHeap( //保存堆栈信息
retainedReferenceCount = retainedReferenceCount,
retry = true,
reason = "$retainedReferenceCount retained objects, app is $visibility"
)
}
onActivityDestroyed事件生成activity描述信息清理引用表中已经被回收的对象:循环从ReferenceQueue中取出已经被回收的引用,并从引用表中删除通过UUID.randomUUID()生成key构建弱引用KeyedWeakReference,并关联ReferenceQueue,弱引用持有监控对象、key、描述信息、监控时间。当监控对象被回收后,弱引用会被添加到ReferenceQueue弱引用添加到引用表(map)中:watchedObjects[key] = reference再次清理引用表中已经被回收的对象从引用表中取出监控对象:watchedObjects[key]更新泄漏检测时间retainedUptimeMillisyes引用表中还存在表示泄漏是否泄漏?no清理引用表中已经被回收的对象获取泄漏对象数量:引用表中retainedUptimeMillis已被更新的引用数量onObjectRetained()后台线程执行checkRetainedObjects()Runtime.getRuntime().gc()重新获取泄漏对象数量yes泄漏对象数量大于0?Debug.dumpHprofData(heapDumpFile)保存堆栈到文件BackgroundThreadHeapAnalyzer解析堆栈dumpHeap()泄漏对象数量大于阈值(默认5)?no主线程延时5秒执行moveToRetained()调用expectWeaklyReachable()调用scheduleRetainedObjectCheck()ActivityWatcherObjectWatcherInternalLeakCanaryHeapDumpTrigger

Service泄漏监控

Activity可以通过Application注册生命周期事件回调来监控Activity的销毁,但是Service没有这样的机制,需要采用hook系统AMS方式来监控Service的销毁。

Service的内存泄漏监控分为两个阶段:onServicePreDestroy和onServiceDestroyed。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private fun onServicePreDestroy(
token: IBinder,
service: Service
) {
servicesToBeDestroyed[token] = WeakReference(service)
}

private fun onServiceDestroyed(token: IBinder) {
servicesToBeDestroyed.remove(token)?.also { serviceWeakReference ->
serviceWeakReference.get()?.let { service ->
reachabilityWatcher.expectWeaklyReachable(
service, "${service::class.java.name} received Service#onDestroy() callback"
)
}
}
}

从代码中可以看出onServicePreDestroy的作用是把service对象通过弱引用保存到map中,然后在onServiceDestroyed中取出service对象,并触发泄漏检测逻辑。

onServicePreDestroy获取service实例

Service的创建、绑定、停止都会走到ActivityThread.H类,ActivityThread相关代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
public final class ActivityThread extends ClientTransactionHandler
implements ActivityThreadInternal {
......
final H mH = new H();
......
@UnsupportedAppUsage
final ArrayMap<IBinder, Service> mServices = new ArrayMap<>();
......
class H extends Handler {
......
@UnsupportedAppUsage
public static final int CREATE_SERVICE = 114; //创建服务
@UnsupportedAppUsage
public static final int SERVICE_ARGS = 115; //Service#onStartCommand
@UnsupportedAppUsage
public static final int STOP_SERVICE = 116; //停止服务
......
@UnsupportedAppUsage
public static final int BIND_SERVICE = 121; //绑定服务
@UnsupportedAppUsage
public static final int UNBIND_SERVICE = 122; //解绑
......
public void handleMessage(Message msg) {
switch (msg.what) {
......
case STOP_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceStop");
handleStopService((IBinder)msg.obj);
schedulePurgeIdler();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
......
}
......
}
}
}

public class Handler {
......
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) { //返回false,还会继续执行后面的handleMessage
return;
}
}
handleMessage(msg);
}
}
......

通过反射替换掉ActivityThread.mH.mCallback,替换后的Callback如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//ServiceWatcher.kt
override fun install() {
......
try {
swapActivityThreadHandlerCallback { mCallback ->
uninstallActivityThreadHandlerCallback = {
swapActivityThreadHandlerCallback {
mCallback
}
}
Handler.Callback { msg ->
if (msg.obj !is IBinder) {
return@Callback false //返回false后,继续执行H类的消息处理
}

if (msg.what == STOP_SERVICE) {
val key = msg.obj as IBinder
activityThreadServices[key]?.let { //获取service实例
onServicePreDestroy(key, it)
}
}
//mCallback就是通过反射获取的ActivityThread.mH.mCallback
mCallback?.handleMessage(msg) ?: false
}
}

通过mH.mCallback只能拿到service的token,并没有拿到service实例。service实例的获取是通过反射获取ActivityThread中的mServices。

1
2
3
4
5
6
7
private val activityThreadServices by lazy {
val mServicesField =
activityThreadClass.getDeclaredField("mServices").apply { isAccessible = true }

@Suppress("UNCHECKED_CAST")
mServicesField[activityThreadInstance] as Map<IBinder, Service>
}

通过ActivityThread.mH反射方式可以拿到Service的停止事件,这是service stop开始执行的时机,此时可以从ActivityThread.mServices获取到service实例,之后service实例就会从map中删除,就再也拿不到了,这就是分成了onServicePreDestroy和onServiceDestroyed两个阶段的根本原因。

onServiceDestroyed监控Service destroy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//frameworks\base\core\java\android\app\ActivityThread.java
private void handleStopService(IBinder token) {
mServicesData.remove(token);
Service s = mServices.remove(token);
if (s != null) {
try {
if (localLOGV) Slog.v(TAG, "Destroying service " + s);
s.onDestroy(); //执行Service#onDestroy
s.detachAndCleanUp();
Context context = s.getBaseContext();
if (context instanceof ContextImpl) {
final String who = s.getClassName();
((ContextImpl) context).scheduleFinalCleanup(who, "Service");
}

QueuedWork.waitToFinish();

try {
//Service#onDestroy执行完成后的最终时机
ActivityManager.getService().serviceDoneExecuting(
token, SERVICE_DONE_EXECUTING_STOP, 0, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(s, e)) {
throw new RuntimeException(
"Unable to stop service " + s
+ ": " + e.toString(), e);
}
Slog.i(TAG, "handleStopService: exception for " + token, e);
}
} else {
Slog.i(TAG, "handleStopService: token=" + token + " not found.");
}
//Slog.i(TAG, "Running services: " + mServices);
}

从上述代码可以看出Service停止最后执行的是ActivityManager.getService().serviceDoneExecuting

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//frameworks\base\core\java\android\app\ActivityManager.java
@SystemService(Context.ACTIVITY_SERVICE)
public class ActivityManager {
......
@UnsupportedAppUsage
public static IActivityManager getService() {
return IActivityManagerSingleton.get();
}
@UnsupportedAppUsage
private static final Singleton<IActivityManager> IActivityManagerSingleton =
new Singleton<IActivityManager>() {
@Override
protected IActivityManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
final IActivityManager am = IActivityManager.Stub.asInterface(b);
return am;
}
};
androidosBinderIActivityManagerserviceDoneExecuting()由IActivityManager.aidl生成StubserviceDoneExecuting()IActivityManager内部静态类ActivityManagerServiceActiveServicesserviceDoneExecutingLocked()

LeakCanary通过动态代理IActivityManager接口的方式来hook serviceDoneExecuting。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
//ServiceWatcher.kt
override fun install() {
......
swapActivityManager { activityManagerInterface, activityManagerInstance ->
uninstallActivityManager = {
swapActivityManager { _, _ ->
activityManagerInstance
}
}
Proxy.newProxyInstance(
activityManagerInterface.classLoader, arrayOf(activityManagerInterface)
) { _, method, args ->
if (METHOD_SERVICE_DONE_EXECUTING == method.name) {
val token = args!![0] as IBinder
if (servicesToBeDestroyed.containsKey(token)) {
onServiceDestroyed(token)
}
}
try {
if (args == null) {
method.invoke(activityManagerInstance)
} else {
method.invoke(activityManagerInstance, *args)
}
} catch (invocationException: InvocationTargetException) {
throw invocationException.targetException
}
}
}
......
}

private fun onServiceDestroyed(token: IBinder) {
servicesToBeDestroyed.remove(token)?.also { serviceWeakReference ->
serviceWeakReference.get()?.let { service ->
reachabilityWatcher.expectWeaklyReachable( //后面步骤就和activity的相同了
service, "${service::class.java.name} received Service#onDestroy() callback"
)
}
}
}

Fragment泄漏监控

Fragment的监控是先接收onActivityCreated事件,然后通过activity拿到FragmentManager,然后注册FragmentLifecycleCallbacks,通过onFragmentViewDestroyed回调事件来监控fragment view的内存泄漏,通过onFragmentDestroyed回调事件来监控fragment的泄漏。

FragmentAndViewModelWatcherAndroidOFragmentDestroyWatcherAndroid 8.0及以上AndroidXFragmentDestroyWatcherAndroidX supportViewModelClearedWatcherAndroidSupportFragmentDestroyWatchersupport.v4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
internal class AndroidOFragmentDestroyWatcher(
private val reachabilityWatcher: ReachabilityWatcher
) : (Activity) -> Unit {
private val fragmentLifecycleCallbacks = object : FragmentManager.FragmentLifecycleCallbacks() {

override fun onFragmentViewDestroyed(
fm: FragmentManager,
fragment: Fragment
) {
val view = fragment.view
if (view != null) {
reachabilityWatcher.expectWeaklyReachable(
view, "${fragment::class.java.name} received Fragment#onDestroyView() callback " +
"(references to its views should be cleared to prevent leaks)"
)
}
}

override fun onFragmentDestroyed(
fm: FragmentManager,
fragment: Fragment
) {
reachabilityWatcher.expectWeaklyReachable(
fragment, "${fragment::class.java.name} received Fragment#onDestroy() callback"
)
}
}

override fun invoke(activity: Activity) {
val fragmentManager = activity.fragmentManager
fragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true)
}
}

ViewModel泄漏监控

在AndroidXFragmentDestroyWatcher中初始化ViewModel的泄漏监控。ViewModelClearedWatcher继承自ViewModel。

ViewModelvoid onCleared()ViewModelClearedWatcherViewModelStoreOwnerViewModelStore getViewModelStore()FragmentActivityViewModelStoreHashMap<String, ViewModel> mMapViewModelStoreHashMap<String, ViewModel> mMapFragment11添加到

FragmentActivity和Fragment都是ViewModelStoreOwner,所以在两者的create时机都会创建ViewModelClearedWatcher,并注册。ViewModelClearedWatcher本身也是一个ViewModel,当ViewModelClearedWatcher#onCleared被调用时,ViewModelStoreOwner中注册的ViewModel都会被clear。所以onCleared时,通过反射拿到ViewModelStore#mMap,将map中所有的ViewModel进行泄漏监控。

RootView泄漏监控

RootViewWatcher实现了对RootView内存泄漏的监控。原理是:WindowManagerGlobal#mViews就是存放DecorView的列表,通过反射把mViews替换为自定义的ArrayList。然后在WindowManagerGlobal#addViewWindowManagerGlobal#removeView就可以执行到自定义ArrayList的add和remove方法,从而得到RootView的添加和删除时机,从而触发内存泄漏检测逻辑。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public final class WindowManagerGlobal {
......
@UnsupportedAppUsage
private final ArrayList<View> mViews = new ArrayList<View>();
......
@UnsupportedAppUsage
public static WindowManagerGlobal getInstance() {
synchronized (WindowManagerGlobal.class) {
if (sDefaultWindowManager == null) {
sDefaultWindowManager = new WindowManagerGlobal();
}
return sDefaultWindowManager;
}
}

RootViewWatcher会监听rootView的添加时机,然后调用rootView.addOnAttachStateChangeListener来接收onViewAttachedToWindow和onViewDetachedFromWindow事件。当onViewDetachedFromWindow时就会去检测是否发生内存泄漏。

参考资料

java 源码系列 - 带你读懂 Reference 和 ReferenceQueue