本文基于LeakCanary 2.12进行分析。
Application ActivityLifecycleCallbacks ReachabilityWatcher ObjectWatcher watchedObjects : Map<String, KeyedWeakReference> queue : ReferenceQueue<Any> KeyedWeakReference WeakReference InstallableWatcher ActivityWatcher FragmentAndViewModelWatcher RootViewWatcher ServiceWatcher AppWatcher 1 n 1 n
初始化 引入LeakCanary时,只需要引入maven库的坐标即可,如下:
1 2 3 4 dependencies { 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() } LeakCanaryDelegate.loadLeakCanary(application) watchersToInstall.forEach { it.install() } 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) ) }
Activity泄漏监视 Activity的内存泄漏通过ActivityWatcher来监控。下图是Activity泄漏监控相关类图结构:
ReachabilityWatcher ActivityWatcher ObjectWatcher KeyedWeakReference OnObjectRetainedListener onObjectRetained() «Singleton» InternalLeakCanary void sendEvent(Event) HeapDumpTrigger EventListener onEvent() «Singleton» BackgroundThreadHeapAnalyzer «Singleton» LogcatEventListener «Singleton» ToastEventListener «Singleton» AndroidDebugHeapAnalyzer 1 n 1 n
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 ) : InstallableWatcher { private val lifecycleCallbacks = object : Application.ActivityLifecycleCallbacks by noOpDelegate() { override fun onActivityDestroyed (activity: Activity ) { reachabilityWatcher.expectWeaklyReachable( activity, "${activity::class.java.name} received Activity#onDestroy() callback" ) } } 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() val reference = KeyedWeakReference(watchedObject, key, description, watchUptimeMillis, queue) ...... watchedObjects[key] = reference checkRetainedExecutor.execute { moveToRetained(key) } }
通过一个弱引用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" } 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() val retainedRef = watchedObjects[key] if (retainedRef != null ) { retainedRef.retainedUptimeMillis = clock.uptimeMillis() onObjectRetainedListeners.forEach { it.onObjectRetained() } } } private fun removeWeaklyReachableObjects () { var ref: KeyedWeakReference? do { ref = queue.poll() as KeyedWeakReference? if (ref != null ) { watchedObjects.remove(ref.key) } } while (ref != null ) }
当检测到对象没有被回收后,会调用leakcanary.internal.InternalLeakCanary#onObjectRetained
来触发泄漏检测:
1 2 3 4 5 6 7 8 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 fun scheduleRetainedObjectCheck ( delayMillis: Long = 0 L ) { 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() retainedReferenceCount = objectWatcher.retainedObjectCount } if (checkRetainedCount(retainedReferenceCount, config.retainedVisibleThreshold)) return val now = SystemClock.uptimeMillis() val elapsedSinceLastDumpMillis = now - lastHeapDumpUptimeMillis 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] 更新泄漏检测时间 retainedUptimeMillis yes 引用表中还存在 表示泄漏 是否泄漏? no 清理引用表中已经被回收的对象 获取泄漏对象数量:引用表中retainedUptimeMillis 已被更新的引用数量 onObjectRetained() 后台线程执行checkRetainedObjects() Runtime.getRuntime().gc() 重新获取泄漏对象数量 yes 泄漏对象数量大于0? Debug.dumpHprofData(heapDumpFile) 保存堆栈到文件 BackgroundThreadHeapAnalyzer 解析堆栈 dumpHeap() 泄漏对象数量大于阈值(默认5)? no 主线程延时5秒执行 moveToRetained() 调用expectWeaklyReachable() 调用scheduleRetainedObjectCheck() ActivityWatcher ObjectWatcher InternalLeakCanary HeapDumpTrigger
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 ; @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)) { 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 override fun install () { ...... try { swapActivityThreadHandlerCallback { mCallback -> uninstallActivityThreadHandlerCallback = { swapActivityThreadHandlerCallback { mCallback } } Handler.Callback { msg -> if (msg.obj !is IBinder) { return @Callback false } if (msg.what == STOP_SERVICE) { val key = msg.obj as IBinder activityThreadServices[key]?.let { onServicePreDestroy(key, it) } } 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 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(); s.detachAndCleanUp(); Context context = s.getBaseContext(); if (context instanceof ContextImpl) { final String who = s.getClassName(); ((ContextImpl) context).scheduleFinalCleanup(who, "Service" ); } QueuedWork.waitToFinish(); try { 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." ); } }
从上述代码可以看出Service停止最后执行的是ActivityManager.getService().serviceDoneExecuting
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @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; } };
android os Binder IActivityManager serviceDoneExecuting() 由IActivityManager.aidl生成 Stub serviceDoneExecuting() IActivityManager 内部静态类 ActivityManagerService ActiveServices serviceDoneExecutingLocked()
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 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( service, "${service::class.java.name} received Service#onDestroy() callback" ) } } }
Fragment泄漏监控 Fragment的监控是先接收onActivityCreated事件,然后通过activity拿到FragmentManager,然后注册FragmentLifecycleCallbacks,通过onFragmentViewDestroyed回调事件来监控fragment view的内存泄漏,通过onFragmentDestroyed回调事件来监控fragment的泄漏。
FragmentAndViewModelWatcher AndroidOFragmentDestroyWatcher Android 8.0及以上 AndroidXFragmentDestroyWatcher AndroidX support ViewModelClearedWatcher AndroidSupportFragmentDestroyWatcher support.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。
ViewModel void onCleared() ViewModelClearedWatcher ViewModelStoreOwner ViewModelStore getViewModelStore() FragmentActivity ViewModelStore HashMap<String, ViewModel> mMap ViewModelStore HashMap<String, ViewModel> mMap Fragment 1 1 添加到
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#addView
和WindowManagerGlobal#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