LeakCanary 是一个 Android 平台的内存泄露分析工具,方便应用开发者找出内存泄漏问题。
源码基于 com.squareup.leakcanary:leakcanary-android:2.7。
LeakCanary 初始化 LeakCanary 通过 ContentProvider 完成自动初始化。
1 2 3 4 5 6 7 8 9 10 11 <manifest xmlns:android ="http://schemas.android.com/apk/res/android" package ="com.squareup.leakcanary.objectwatcher" > <application > <provider android:name ="leakcanary.internal.AppWatcherInstaller$MainProcess" android:authorities ="${applicationId}.leakcanary-installer" android:enabled ="@bool/leak_canary_watcher_auto_install" android:exported ="false" /> </application > </manifest >
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 internal sealed class AppWatcherInstaller : ContentProvider () { internal class MainProcess : AppWatcherInstaller () internal class LeakCanaryProcess : AppWatcherInstaller () override fun onCreate () : Boolean { val application = context!!.applicationContext as Application AppWatcher.manualInstall(application) return true } } object AppWatcher { fun manualInstall ( application: Application , retainedDelayMillis: Long = TimeUnit.SECONDS.toMillis(5 ) , watchersToInstall: List<InstallableWatcher> = appDefaultWatchers(application)) { checkMainThread() LeakCanaryDelegate.loadLeakCanary(application) watchersToInstall.forEach { it.install() } } fun appDefaultWatchers (...) : List<InstallableWatcher> { return listOf( ActivityWatcher(application, reachabilityWatcher), FragmentAndViewModelWatcher(application, reachabilityWatcher), RootViewWatcher(reachabilityWatcher), ServiceWatcher(reachabilityWatcher) ) } } internal object LeakCanaryDelegate { val loadLeakCanary by lazy { val leakCanaryListener = Class.forName("leakcanary.internal.InternalLeakCanary" ) leakCanaryListener.getDeclaredField("INSTANCE" ) .get (null ) as (Application) -> Unit } } internal object InternalLeakCanary : (Application) -> Unit , OnObjectRetainedListener { override fun invoke (application: Application ) { AppWatcher.objectWatcher.addOnObjectRetainedListener(this ) val heapDumper = AndroidHeapDumper(application, createLeakDirectoryProvider(application)) heapDumpTrigger = HeapDumpTrigger( application, backgroundHandler, AppWatcher.objectWatcher, gcTrigger, heapDumper, configProvider) addDynamicShortcut(application) } }
InternalLeakCanary 的部分声明为 object InternalLeakCanary : (Application) -> Unit,对应 kotlin 中 Functions.kt 文件的 Function1 接口,P1 为 Application,R 为 Unit 即 void:
1 2 3 4 5 public interface Function1 <in P1, out R > : Function <R > { public operator fun invoke (p1: P1 ) : R }
观察对象 观察 Activity 对象 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 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) } }
通过 Application.ActivityLifecycleCallbacks#onActivityDestroyed() 监听 Activity 对象。
观察 Fragment 对象 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 class FragmentAndViewModelWatcher ( private val application: Application, private val reachabilityWatcher: ReachabilityWatcher ) : InstallableWatcher { private val fragmentDestroyWatchers: List<(Activity) -> Unit > = run { val fragmentDestroyWatchers = mutableListOf<(Activity) -> Unit >() if (SDK_INT >= O) { fragmentDestroyWatchers.add(AndroidOFragmentDestroyWatcher(reachabilityWatcher)) } getWatcherIfAvailable( ANDROIDX_FRAGMENT_CLASS_NAME, ANDROIDX_FRAGMENT_DESTROY_WATCHER_CLASS_NAME, reachabilityWatcher )?.let { fragmentDestroyWatchers.add(it) } getWatcherIfAvailable( ANDROID_SUPPORT_FRAGMENT_CLASS_NAME, ANDROID_SUPPORT_FRAGMENT_DESTROY_WATCHER_CLASS_NAME, reachabilityWatcher )?.let { fragmentDestroyWatchers.add(it) } fragmentDestroyWatchers } private val lifecycleCallbacks = object : Application.ActivityLifecycleCallbacks by noOpDelegate() { override fun onActivityCreated (activity: Activity , savedInstanceState: Bundle ? ) { for (watcher in fragmentDestroyWatchers) { watcher(activity) } } } override fun install () { application.registerActivityLifecycleCallbacks(lifecycleCallbacks) } override fun uninstall () { application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks) } }
通过 FragmentLifecycleCallbacks#onFragmentViewDestroyed() 和 onFragmentDestroyed() 监听 View 和 Fragment 对象。
观察 RootView 对象 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 class RootViewWatcher ( private val reachabilityWatcher: ReachabilityWatcher ) : InstallableWatcher { private val listener = OnRootViewAddedListener { rootView -> val trackDetached = when (rootView.windowType) { PHONE_WINDOW -> { when (rootView.phoneWindow?.callback?.wrappedCallback) { is Activity -> false is Dialog -> rootView.resources.getBoolean(R.bool.leak_canary_watcher_watch_dismissed_dialogs) else -> true } } POPUP_WINDOW -> false TOOLTIP, TOAST, UNKNOWN -> true } if (trackDetached) { rootView.addOnAttachStateChangeListener(object : OnAttachStateChangeListener { val watchDetachedView = Runnable { reachabilityWatcher.expectWeaklyReachable( rootView, "${rootView::class.java.name} received View#onDetachedFromWindow() callback" ) } override fun onViewAttachedToWindow (v: View ) { mainHandler.removeCallbacks(watchDetachedView) } override fun onViewDetachedFromWindow (v: View ) { mainHandler.post(watchDetachedView) } }) } } override fun install () { Curtains.onRootViewsChangedListeners += listener } override fun uninstall () { Curtains.onRootViewsChangedListeners -= listener } }
通过 View.OnAttachStateChangeListener#onViewDetachedFromWindow() 监听 View 对象。
观察 Service 对象 通过 hook 监听 ActivityThread#H 的 STOP_SERVICE 消息,然后记录这个 binder 到弱引用集合中。然后代理 AMS 的 serviceDoneExecuting 方法,通过 binder 在弱引用集合中去移除,移除成功的话,说明发生了内存泄漏。
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 class ServiceWatcher (private val reachabilityWatcher: ReachabilityWatcher) : InstallableWatcher { override fun install () { swapActivityThreadHandlerCallback { mCallback -> Handler.Callback { msg -> if (msg.what == STOP_SERVICE) { val key = msg.obj as IBinder activityThreadServices[key]?.let { onServicePreDestroy(key, it) } } mCallback?.handleMessage(msg) ?: false } } swapActivityManager { activityManagerInterface, 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) } } } } } 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" ) } } } }
通过动态代理,在调用 serviceDoneExecuting 方法时判断 Service 对象是否泄漏。
检测泄漏对象 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 class ObjectWatcher { private val watchedObjects = mutableMapOf<String, KeyedWeakReference>() private val queue = ReferenceQueue<Any>() @Synchronized override fun expectWeaklyReachable (watchedObject: Any , description: String ) { removeWeaklyReachableObjects() val reference = KeyedWeakReference(watchedObject, key, description, watchUptimeMillis, queue) watchedObjects[key] = reference checkRetainedExecutor.execute { moveToRetained(key) } } @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 ) } }
先移除队列中没有泄漏的对象;
把观察对象包装成 KeyedWeakReference 保存到引用队列中;
5s 后弱引用依然存在,可能存在内存泄漏,检测该对象。
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 54 55 internal object InternalLeakCanary : (Application) -> Unit , OnObjectRetainedListener { override fun onObjectRetained () = scheduleRetainedObjectCheck() fun scheduleRetainedObjectCheck () { if (this ::heapDumpTrigger.isInitialized) { heapDumpTrigger.scheduleRetainedObjectCheck() } } } internal class HeapDumpTrigger (...) { fun scheduleRetainedObjectCheck (delayMillis: Long = 0 L) { backgroundHandler.postDelayed({ checkScheduledAt = 0 checkRetainedObjects() }, delayMillis) } private fun checkRetainedObjects () { if (iCanHasHeap is Nope) { return } var retainedReferenceCount = objectWatcher.retainedObjectCount if (retainedReferenceCount > 0 ) { gcTrigger.runGc() retainedReferenceCount = objectWatcher.retainedObjectCount } if (checkRetainedCount(retainedReferenceCount, config.retainedVisibleThreshold)) return if (elapsedSinceLastDumpMillis < WAIT_BETWEEN_HEAP_DUMPS_MILLIS) { showRetainedCountNotification() scheduleRetainedObjectCheck() return } dismissRetainedCountNotification() dumpHeap(...) } private fun dumpHeap (retainedReferenceCount: Int , retry: Boolean , reason: String ) { saveResourceIdNamesToMemory() when (val heapDumpResult = heapDumper.dumpHeap()) { is NoHeapDump -> { showRetainedCountNotification(...) } is HeapDump -> { HeapAnalyzerService.runAnalysis(...) } } } }
GC 后判断引用的对象数量;
泄漏对象 >= 5 时才显示通知,启动 HeapAnalyzerService 服务,dump 内存。
dump 对象和分析 Hprof 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 internal class HeapAnalyzerService : ForegroundService (...), OnAnalysisProgressListener { override fun onHandleIntentInForeground (intent: Intent ?) { val heapAnalysis = if (heapDumpFile.exists()) { analyzeHeap(heapDumpFile, config) } else { missingFileFailure(heapDumpFile) } onAnalysisProgress(REPORTING_HEAP_ANALYSIS) config.onHeapAnalyzedListener.onHeapAnalyzed(fullHeapAnalysis) } private fun analyzeHeap (heapDumpFile: File , config: Config ) : HeapAnalysis { val heapAnalyzer = HeapAnalyzer(this ) return heapAnalyzer.analyze() } } class HeapAnalyzer constructor (private val listener: OnAnalysisProgressListener) { fun analyze (...) { listener.onAnalysisProgress(PARSING_HEAP_DUMP) val sourceProvider = ConstantMemoryMetricsDualSourceProvider(FileSourceProvider(heapDumpFile)) sourceProvider.openHeapGraph(proguardMapping).use { val helpers = FindLeakInput(graph, ...) val result = helpers.analyzeGraph(metadataExtractor, ...) } } }
总结
通过 ContentProvider 初始化 LeakCanary;
在 Activity、Fragment、RootView 和 Service 对象的“终结”生命周期中观察对象;
生成 uuid,把观察的对象包装成弱引用,添加到引用队列;
如果泄漏对象 > 0,触发 GC,GC 后泄漏对象 >= 5 时,显示通知,dump 内存;
通过 shark 库分析 hprof 文件,查找泄露对象引用路径,存储分析结果。
参考 [1] square/leakcanary [2] LeakCanary Doc