1简介:
LeakCanray是Square开源的Java内存泄漏分析工具,用于在开发阶段检测Android应用中常见中的内存泄漏。
debugImplementation
来配置依赖// 普通ContentProvider方式
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.12'
// 可选,使用WorkerManager多进程分析堆快照提升分析速度
debugImplementation 'com.squareup.leakcanary:leakcanary-android-process:2.12'
ContentProvider
的启动机制来间接调用初始化 API, 实现了无侵入的 LeakCanary 初始化。
internal class MainProcessAppWatcherInstaller : ContentProvider() {
override fun onCreate(): Boolean {
val application = context!!.applicationContext as Application
// LeakCanary初始化代码
AppWatcher.manualInstall(application)
return true
}
...
}
真正的初始化代码为AppWatcher.manualInstall(application)
// AppWatcher.kt
/** LeakCanary初始化 */
@JvmOverloads
fun manualInstall(
application: Application,
retainedDelayMillis: Long = TimeUnit.SECONDS.toMillis(5), // 默认5s后进行泄漏检测
watchersToInstall: List = appDefaultWatchers(application)
) {
checkMainThread()
...
// 初始化 InternalLeakCanary 内部引擎
LeakCanaryDelegate.loadLeakCanary(application)
// 遍历五种监听器进行分别注册
watchersToInstall.forEach {
it.install()
}
...
}
/** 创建监听集合 */
fun appDefaultWatchers(
application: Application,
reachabilityWatcher: ReachabilityWatcher = objectWatcher
): List {
return listOf(
// 对应5中Android泄漏场景(Activity、Fragment和ViewModel、View、Service)
// 传入的reachabilityWatcher均为ReachabilityWatcher的唯一实现类ObjectWatcher
ActivityWatcher(application, reachabilityWatcher),
FragmentAndViewModelWatcher(application, reachabilityWatcher),
RootViewWatcher(reachabilityWatcher),
ServiceWatcher(reachabilityWatcher)
)
}
分为四个监控类分别对Activity、Fragment和ViewModel、RootView以及Service分别监控,接下来分析下这四个类是如何具体监控的
/** Activity的泄漏监听 */
class ActivityWatcher(
private val application: Application,
private val reachabilityWatcher: ReachabilityWatcher
) : InstallableWatcher {
private val lifecycleCallbacks =
object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
override fun onActivityDestroyed(activity: Activity) {
// 交给objectWatcher分析
reachabilityWatcher.expectWeaklyReachable(
activity, "${activity::class.java.name} received Activity#onDestroy() callback"
)
}
}
override fun install() {
// 注册监听的方式
application.registerActivityLifecycleCallbacks(lifecycleCallbacks)
}
override fun uninstall() {
application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks)
}
}
application.registerActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback)
即可,然后在每个Activity的onDestroy中将activity交给objectWatcher去分析即可/**
* 主要负责Fragment的泄漏监听(通过Fragment.onDestroy())
* Fragment View的泄漏监听(通过Fragment.onDestroyView())
* ViewModel的泄漏监听(通过ViewModel.onCleared())
*/
class FragmentAndViewModelWatcher(
private val application: Application,
private val reachabilityWatcher: ReachabilityWatcher
) : InstallableWatcher {
/** Fragment监测集合(主要包含几种包下的Fragment) */
// 集合的类型是(Activity)->Unit的函数类型
private val fragmentDestroyWatchers: List<(Activity) -> Unit> = run {
val fragmentDestroyWatchers = mutableListOf<(Activity) -> Unit>()
// Android O(8.0)后使用AndroidOFragmentDestroyWatcher监听
if (SDK_INT >= O) {
fragmentDestroyWatchers.add(
AndroidOFragmentDestroyWatcher(reachabilityWatcher)
)
}
// androidx包下的Fragment使用AndroidXFragmentDestroyWatcher监听
getWatcherIfAvailable(
ANDROIDX_FRAGMENT_CLASS_NAME,
ANDROIDX_FRAGMENT_DESTROY_WATCHER_CLASS_NAME,
reachabilityWatcher
)?.let {
fragmentDestroyWatchers.add(it)
}
// android.support.v4包下的Fragment使用AndroidSupportFragmentDestroyWatcher监听
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?
) {
// 监听每个Activity的onActivityCreated(),再在其中进行Fragment监听
for (watcher in fragmentDestroyWatchers) {
// 由于fragmentDestroyWatchers里面本身存储的是一个(Activity)->Unit的函数类型
// 所以这里可以直接使用watcher(activity),直接调用,参数为activity,
// 实际执行的是watcher中的invoke()
watcher(activity)
}
}
}
override fun install() {
application.registerActivityLifecycleCallbacks(lifecycleCallbacks)
}
override fun uninstall() {
application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks)
}
...
}
FragmentAndViewModelWatcher
实现,首先是通过 Application.registerActivityLifecycleCallbacks(…)
接口监听 Activity.onCreate()事件,再通过 FragmentManager.registerFragmentLifecycleCallbacks(…)
接口监听 Fragment 的生命周期AndroidOFragmentDestroyWatcher
、AndroidXFragmentDestroyWatcher
、AndroidSupportFragmentDestroyWatcher
,这里以AndroidXFragmentDestroyWatcher为例/** Androidx包下的Fragment、FragmentView以及ViewModel监听 */
internal class AndroidXFragmentDestroyWatcher(
private val reachabilityWatcher: ReachabilityWatcher
) : (Activity) -> Unit {
private val fragmentLifecycleCallbacks = object : FragmentManager.FragmentLifecycleCallbacks() {
override fun onFragmentCreated(
fm: FragmentManager,
fragment: Fragment,
savedInstanceState: Bundle?
) {
// 注册Fragment级别的ViewModel Hook
ViewModelClearedWatcher.install(fragment, reachabilityWatcher)
}
override fun onFragmentViewDestroyed(
fm: FragmentManager,
fragment: Fragment
) {
val view = fragment.view
if (view != null) {
// 监听FragmentView.onDestroy()将Fragment.View交给ObjectWatcher分析
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
) {
// 监听Fragment.onDestroy()将Fragment交给ObjectWatcher分析
reachabilityWatcher.expectWeaklyReachable(
fragment, "${fragment::class.java.name} received Fragment#onDestroy() callback"
)
}
}
override fun invoke(activity: Activity) {
// 这段代码会在Activity.onCreate()中执行
if (activity is FragmentActivity) {
val supportFragmentManager = activity.supportFragmentManager
// 注册Fragment生命周期监听
supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true)
// 注册Activity级别的ViewModel Hook
ViewModelClearedWatcher.install(activity, reachabilityWatcher)
}
}
}
ViewModelClearedWatcher
进行监听,由于系统并未提供ViewModel全局监听的方法,所以 ViewModelClearedWatcher 是通过Hook
方式实现的,我们看下ViewModelClearedWatcherinternal class ViewModelClearedWatcher(
storeOwner: ViewModelStoreOwner,
private val reachabilityWatcher: ReachabilityWatcher
) : ViewModel() {
// 直接通过反射获取ViewModelStore类中的map变量(后面改成mMap),即可获得作用域中的所有ViewModel对象
private val viewModelMap: Map? = try {
val storeClass = ViewModelStore::class.java
val mapField = try {
storeClass.getDeclaredField("map")
} catch (exception: NoSuchFieldException) {
storeClass.getDeclaredField("mMap")
}
mapField.isAccessible = true
@Suppress("UNCHECKED_CAST")
mapField[storeOwner.viewModelStore] as Map
} catch (ignored: Exception) {
SharkLog.d(ignored) { "Could not find ViewModelStore map of view models" }
null
}
override fun onCleared() {
// 遍历当前作用域所有ViewModel对象
viewModelMap?.values?.forEach { viewModel ->
// 使用ObjectWatcher.expectWeaklyReachable
reachabilityWatcher.expectWeaklyReachable(
viewModel, "${viewModel::class.java.name} received ViewModel#onCleared() callback"
)
}
}
companion object {
// 在storeOwner作用域实例化ViewModelClearedWatcher对象
fun install(
storeOwner: ViewModelStoreOwner,
reachabilityWatcher: ReachabilityWatcher
) {
val provider = ViewModelProvider(storeOwner, object : Factory {
@Suppress("UNCHECKED_CAST")
override fun create(modelClass: Class): T =
// 直接在storeOwner作用域实例化ViewModelClearedWatcher对象
ViewModelClearedWatcher(storeOwner, reachabilityWatcher) as T
})
provider.get(ViewModelClearedWatcher::class.java)
}
}
}
WindowManagerGlobal
(sdk>16)或者 WindowManagerImpl
(sdk<=16)来获取所有的RootView新增或移除的时机/**
* RootView泄漏监听,主要利用了Curtains库实现对
*/
class RootViewWatcher(
private val reachabilityWatcher: ReachabilityWatcher
) : InstallableWatcher {
private val listener = OnRootViewAddedListener { rootView ->
// 判断rootView的窗口类型
// 是否需要使用RootViewWatcher监听
val trackDetached = when(rootView.windowType) {
PHONE_WINDOW -> {
when (rootView.phoneWindow?.callback?.wrappedCallback) {
// Activities are already tracked by ActivityWatcher
// 由于Activity已经有ActivityWatcher监听,这里直接返回false,即无需通过RootViewWatcher监听
is Activity -> false
is Dialog -> {
// Use app context resources to avoid NotFoundException
// https://github.com/square/leakcanary/issues/2137
// 通过配置开启,默认不开启
val resources = rootView.context.applicationContext.resources
resources.getBoolean(R.bool.leak_canary_watcher_watch_dismissed_dialogs)
}
// Probably a DreamService
// 屏保等
else -> true
}
}
// Android widgets keep detached popup window instances around.
POPUP_WINDOW -> false
// Tooltip、Toast等进行监听
TOOLTIP, TOAST, UNKNOWN -> true
}
if (trackDetached) {
// 注册监听事件
rootView.addOnAttachStateChangeListener(object : OnAttachStateChangeListener {
val watchDetachedView = Runnable {
// 接收发送的消息,使用ObjectWatcher对rootView进行监听
reachabilityWatcher.expectWeaklyReachable(
rootView, "${rootView::class.java.name} received View#onDetachedFromWindow() callback"
)
}
override fun onViewAttachedToWindow(v: View) {
// 添加时移除消息
mainHandler.removeCallbacks(watchDetachedView)
}
override fun onViewDetachedFromWindow(v: View) {
// 监听RootView的移除事件,使用Handler发送消息处理
mainHandler.post(watchDetachedView)
}
})
}
}
override fun install() {
// 注册RootView监听
Curtains.onRootViewsChangedListeners += listener
}
override fun uninstall() {
Curtains.onRootViewsChangedListeners -= listener
}
}
Dialog(有监听开关配置)、DreamService、Tooltip、Toast
等类型的RootView进行监听,通过调用rootView.addOnAttachStateChangeListener
监听onViewDetachedFromWindow
方法,监听RootView的移除事件,在移除事件中将RootView交给ObjectWatcher进行监控@SuppressLint("PrivateApi")
class ServiceWatcher(private val reachabilityWatcher: ReachabilityWatcher) : InstallableWatcher {
private val servicesToBeDestroyed = WeakHashMap>()
private val activityThreadClass by lazy { Class.forName("android.app.ActivityThread") }
private val activityThreadInstance by lazy {
activityThreadClass.getDeclaredMethod("currentActivityThread").invoke(null)!!
}
private val activityThreadServices by lazy {
val mServicesField =
activityThreadClass.getDeclaredField("mServices").apply { isAccessible = true }
@Suppress("UNCHECKED_CAST")
mServicesField[activityThreadInstance] as Map
}
private var uninstallActivityThreadHandlerCallback: (() -> Unit)? = null
private var uninstallActivityManager: (() -> Unit)? = null
override fun install() {
checkMainThread()
check(uninstallActivityThreadHandlerCallback == null) {
"ServiceWatcher already installed"
}
check(uninstallActivityManager == null) {
"ServiceWatcher already installed"
}
try {
// Hook ActivityThread类中的mH.mCallback
swapActivityThreadHandlerCallback { mCallback ->
uninstallActivityThreadHandlerCallback = {
swapActivityThreadHandlerCallback {
mCallback
}
}
Handler.Callback { msg ->
if (msg.obj !is IBinder) {
return@Callback false
}
// 监听Service.onStop()事件消息
if (msg.what == STOP_SERVICE) {
val key = msg.obj as IBinder
// activityThreadServices是通过反射获取的ActivityThread类中的mServices成员变量
activityThreadServices[key]?.let {
// 服务销毁前的处理,这里主要是暂存
onServicePreDestroy(key, it)
}
}
// Hook后继续执行Framework本身的逻辑
mCallback?.handleMessage(msg) ?: false
}
}
// Hook AMS IActivityManager
swapActivityManager { activityManagerInterface, activityManagerInstance ->
uninstallActivityManager = {
swapActivityManager { _, _ ->
activityManagerInstance
}
}
Proxy.newProxyInstance(
activityManagerInterface.classLoader, arrayOf(activityManagerInterface)
) { _, method, args ->
// 代理serviceDoneExecuting()方法
if (METHOD_SERVICE_DONE_EXECUTING == method.name) {
val token = args!![0] as IBinder
if (servicesToBeDestroyed.containsKey(token)) {
// 处理Service销毁,主要是将service交给ObjectWatcher进行监控
onServiceDestroyed(token)
}
}
// 继续执行serviceDoneExecuting()本身的方法
try {
if (args == null) {
method.invoke(activityManagerInstance)
} else {
method.invoke(activityManagerInstance, *args)
}
} catch (invocationException: InvocationTargetException) {
throw invocationException.targetException
}
}
}
} catch (ignored: Throwable) {
SharkLog.d(ignored) { "Could not watch destroyed services" }
}
}
override fun uninstall() {
checkMainThread()
uninstallActivityManager?.invoke()
uninstallActivityThreadHandlerCallback?.invoke()
uninstallActivityManager = null
uninstallActivityThreadHandlerCallback = null
}
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"
)
}
}
}
/**
* Hook修改ActivityThread类中的mH.mCallback
* swap 是一个 lambda 表达式,参数为原对象,返回值为注入的新对象
*/
private fun swapActivityThreadHandlerCallback(swap: (Handler.Callback?) -> Handler.Callback?) {
val mHField =
activityThreadClass.getDeclaredField("mH").apply { isAccessible = true }
val mH = mHField[activityThreadInstance] as Handler
val mCallbackField =
Handler::class.java.getDeclaredField("mCallback").apply { isAccessible = true }
val mCallback = mCallbackField[mH] as Handler.Callback?
mCallbackField[mH] = swap(mCallback)
}
/**
* Hook修改ActivityThread类中的mH.mCallback
* swap 是一个 lambda 表达式,参数为 IActivityManager 的 Class 对象和接口原实现对象,返回值为注入的新对象
*/
@SuppressLint("PrivateApi")
private fun swapActivityManager(swap: (Class<*>, Any) -> Any) {
val singletonClass = Class.forName("android.util.Singleton")
val mInstanceField =
singletonClass.getDeclaredField("mInstance").apply { isAccessible = true }
val singletonGetMethod = singletonClass.getDeclaredMethod("get")
val (className, fieldName) = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
"android.app.ActivityManager" to "IActivityManagerSingleton"
} else {
"android.app.ActivityManagerNative" to "gDefault"
}
val activityManagerClass = Class.forName(className)
val activityManagerSingletonField =
activityManagerClass.getDeclaredField(fieldName).apply { isAccessible = true }
val activityManagerSingletonInstance = activityManagerSingletonField[activityManagerClass]
val activityManagerInstance = singletonGetMethod.invoke(activityManagerSingletonInstance)
val iActivityManagerInterface = Class.forName("android.app.IActivityManager")
// 将swap的返回值作为新对象,实现 Hook
mInstanceField[activityManagerSingletonInstance] =
swap(iActivityManagerInterface, activityManagerInstance!!)
}
companion object {
private const val STOP_SERVICE = 116
private const val METHOD_SERVICE_DONE_EXECUTING = "serviceDoneExecuting"
}
}
mH.mCallback
回调,监听其中的STOP_SERVICE
消息,将即将 Destroy 的 Service 对象暂存起来(由于 ActivityThread.H 中没有 DESTROY_SERVICE 消息,所以不能直接监听到 onDestroy() 事件,需要下面的步骤);IActivityManager
Binder 对象,代理其中的 serviceDoneExecuting()
方法,视为 Service.onDestroy() 的执行时机,拿到暂存的 Service 对象交给 ObjectWatcher 监控。强引用
软引用
SoftReference softReference = new SoftReference<>(str);
弱引用
WeakReference weakReference = new WeakReference<>(str);
虚引用
引用队列ReferenceQueue
// 构造一个强引用
Object obj = new Object();
// 创建引用队列
ReferenceQueue
class ObjectWatcher constructor(
private val clock: Clock,
private val checkRetainedExecutor: Executor,
private val isEnabled: () -> Boolean = { true }
) : ReachabilityWatcher {
private val onObjectRetainedListeners = mutableSetOf()
/** 被监控对象的映射表 */
private val watchedObjects = mutableMapOf()
/** 弱引用引用队列,与KeyedWeakReference相关联,对象正常销毁会存在这里面 */
private val queue = ReferenceQueue()
...
/** 监控对象泄漏 */
@Synchronized
override fun expectWeaklyReachable(
watchedObject: Any,
description: String
) {
if (!isEnabled()) {
return
}
// 移除watchedObjects中未泄漏的对象
removeWeaklyReachableObjects()
// 构造KeyedWeakReference 引用对象
val key = UUID.randomUUID()
.toString()
val watchUptimeMillis = clock.uptimeMillis()
val reference =
KeyedWeakReference(watchedObject, key, description, watchUptimeMillis, queue)
SharkLog.d {
"Watching " +
(if (watchedObject is Class<*>) watchedObject.toString() else "instance of ${watchedObject.javaClass.name}") +
(if (description.isNotEmpty()) " ($description)" else "") +
" with key $key"
}
watchedObjects[key] = reference
// 默认5秒后执行检查
checkRetainedExecutor.execute {
moveToRetained(key)
}
}
...
@Synchronized
private fun moveToRetained(key: String) {
removeWeaklyReachableObjects()
// 移除watchedObjects中未泄露的对象后剩余的判定为发生泄漏
val retainedRef = watchedObjects[key]
if (retainedRef != null) {
retainedRef.retainedUptimeMillis = clock.uptimeMillis()
// 回调通知LeakCanary内部处理
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)
}
}
/** 弱引用包装类 */
class KeyedWeakReference(
/** 被监控对象 */
referent: Any,
/** 映射表的Key */
val key: String,
/** 描述 */
val description: String,
/** 监控开始时间(引用创建时间) */
val watchUptimeMillis: Long,
/** 关联的引用队列 */
referenceQueue: ReferenceQueue
) : WeakReference(
referent, referenceQueue
) {
/** 判定对象为泄漏对象的时间,-1表示非泄漏对象或还未判定完毕 */
@Volatile
var retainedUptimeMillis = -1L
override fun clear() {
super.clear()
retainedUptimeMillis = -1L
}
companion object {
/** 记录最近一次触发Heap Dump的时间 */
@Volatile
@JvmStatic var heapDumpUptimeMillis = 0L
}
}
watchedObject
创建一个 KeyedWeakReference
弱引用,并存储到 retainedUptimeMillis
字段以标记为泄漏onObjectRetained
告知 LeakCanary 内部发生新的内存泄漏OnObjectRetainedListener.onObjectRetained()
回调到 LeakCanary 内部的管理器 InternalLeakCanary
// InternalLeakCanary.kt
override fun onObjectRetained() = scheduleRetainedObjectCheck()
fun scheduleRetainedObjectCheck() {
if (this::heapDumpTrigger.isInitialized) {
heapDumpTrigger.scheduleRetainedObjectCheck()
}
}
// HeapDumpTrigger.kt
fun scheduleRetainedObjectCheck(
delayMillis: Long = 0L
) {
val checkCurrentlyScheduledAt = checkScheduledAt
// 避免重复postDelayed
if (checkCurrentlyScheduledAt > 0) {
return
}
checkScheduledAt = SystemClock.uptimeMillis() + delayMillis
backgroundHandler.postDelayed({
checkScheduledAt = 0
checkRetainedObjects()
}, delayMillis)
}
private fun checkRetainedObjects() {
val iCanHasHeap = HeapDumpControl.iCanHasHeap()
val config = configProvider()
if (iCanHasHeap is Nope) {
if (iCanHasHeap is NotifyingNope) {
// Before notifying that we can't dump heap, let's check if we still have retained object.
// 泄漏计数
var retainedReferenceCount = objectWatcher.retainedObjectCount
// 泄漏计数>0时主动调用GC
if (retainedReferenceCount > 0) {
// 这个方法是调用RunTime.getRuntime().GC()并休眠等待100ms
gcTrigger.runGc()
// GC后再获取泄漏计数
retainedReferenceCount = objectWatcher.retainedObjectCount
}
val nopeReason = iCanHasHeap.reason()
// 这里会判断泄漏计数是否>5(默认阈值)
val wouldDump = !checkRetainedCount(
retainedReferenceCount, config.retainedVisibleThreshold, nopeReason
)
if (wouldDump) {
val uppercaseReason = nopeReason[0].toUpperCase() + nopeReason.substring(1)
// 回调onEvent
onRetainInstanceListener.onEvent(DumpingDisabled(uppercaseReason))
// 展示通知
showRetainedCountNotification(
objectCount = retainedReferenceCount,
contentText = uppercaseReason
)
}
} else {
SharkLog.d {
application.getString(
R.string.leak_canary_heap_dump_disabled_text, iCanHasHeap.reason()
)
}
}
return
}
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
// 计算距离上一次HeapDump时间未超过60s会拦截
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分析
dumpHeap(
retainedReferenceCount = retainedReferenceCount,
retry = true,
reason = "$retainedReferenceCount retained objects, app is $visibility"
)
}
.hprof
堆快照文件,并且发送了一个 LeakCanary 内部事件 HeapDump
。LeakCanary 的配置项中设置了多个事件消费者EventListener,这三个会根据 App 当前的依赖项而选择最优的执行策略:// LeakCanary.kt
val eventListeners: List = listOf(
LogcatEventListener,
ToastEventListener,
LazyForwardingEventListener {
if (InternalLeakCanary.formFactor == TV) TvEventListener else NotificationEventListener
},
when {
// WorkManager多进程分析
RemoteWorkManagerHeapAnalyzer.remoteLeakCanaryServiceInClasspath ->
RemoteWorkManagerHeapAnalyzer
// WorkManager 异步分析
WorkManagerHeapAnalyzer.validWorkManagerInClasspath -> WorkManagerHeapAnalyzer
// 异步线程分析(兜底策略)
else -> BackgroundThreadHeapAnalyzer
}
),
object RemoteWorkManagerHeapAnalyzer : EventListener {
private const val REMOTE_SERVICE_CLASS_NAME = "leakcanary.internal.RemoteLeakCanaryWorkerService"
// 这里通过RemoteLeakCanaryWorkerService这个类是否加载成功来判断
// 是否有'com.squareup.leakcanary:leakcanary-android-process:2.9.1'这个依赖
internal val remoteLeakCanaryServiceInClasspath by lazy {
try {
Class.forName(REMOTE_SERVICE_CLASS_NAME)
true
} catch (ignored: Throwable) {
false
}
}
override fun onEvent(event: Event) {
if (event is HeapDump) {
val application = InternalLeakCanary.application
// 创建并分发 WorkManager 多进程请求
val heapAnalysisRequest =
OneTimeWorkRequest.Builder(RemoteHeapAnalyzerWorker::class.java).apply {
val dataBuilder = Data.Builder()
.putString(ARGUMENT_PACKAGE_NAME, application.packageName)
.putString(ARGUMENT_CLASS_NAME, REMOTE_SERVICE_CLASS_NAME)
setInputData(event.asWorkerInputData(dataBuilder))
with(WorkManagerHeapAnalyzer) {
addExpeditedFlag()
}
}.build()
SharkLog.d { "Enqueuing heap analysis for ${event.file} on WorkManager remote worker" }
val workManager = WorkManager.getInstance(application)
workManager.enqueue(heapAnalysisRequest)
}
}
}
internal class RemoteHeapAnalyzerWorker(appContext: Context, workerParams: WorkerParameters) :
RemoteListenableWorker(appContext, workerParams) {
override fun startRemoteWork(): ListenableFuture {
val heapDump = inputData.asEvent()
val result = SettableFuture.create()
heapAnalyzerThreadHandler.post {
// 分析堆快照
val doneEvent = AndroidDebugHeapAnalyzer.runAnalysisBlocking(heapDump, isCanceled = {
result.isCancelled
}) { progressEvent ->
if (!result.isCancelled) {
// 发送分析进度事件
InternalLeakCanary.sendEvent(progressEvent)
}
}
if (result.isCancelled) {
SharkLog.d { "Remote heap analysis for ${heapDump.file} was canceled" }
} else {
// 发送分析完成事件
InternalLeakCanary.sendEvent(doneEvent)
result.set(Result.success())
}
}
return result
}
override fun getForegroundInfoAsync(): ListenableFuture {
return applicationContext.heapAnalysisForegroundInfoAsync()
}
}
object WorkManagerHeapAnalyzer : EventListener {
// 判断是否包含WorkManager
internal val validWorkManagerInClasspath by lazy {
try {
Class.forName("androidx.work.WorkManager")
val dataBuilderClass = Class.forName("androidx.work.Data$Builder")
dataBuilderClass.declaredMethods.any { it.name == "putByteArray" }.apply {
if (!this) {
SharkLog.d { "Could not find androidx.work.Data$Builder.putByteArray, WorkManager should be at least 2.1.0." }
}
}
} catch (ignored: Throwable) {
false
}
}
// setExpedited() requires WorkManager 2.7.0+
private val workManagerSupportsExpeditedRequests by lazy {
try {
Class.forName("androidx.work.OutOfQuotaPolicy")
true
} catch (ignored: Throwable) {
false
}
}
internal fun OneTimeWorkRequest.Builder.addExpeditedFlag() = apply {
if (workManagerSupportsExpeditedRequests) {
setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
}
}
override fun onEvent(event: Event) {
if (event is HeapDump) {
val heapAnalysisRequest = OneTimeWorkRequest.Builder(HeapAnalyzerWorker::class.java).apply {
setInputData(event.asWorkerInputData())
addExpeditedFlag()
}.build()
SharkLog.d { "Enqueuing heap analysis for ${event.file} on WorkManager remote worker" }
val application = InternalLeakCanary.application
WorkManager.getInstance(application).enqueue(heapAnalysisRequest)
}
}
}
internal class HeapAnalyzerWorker(appContext: Context, workerParams: WorkerParameters) :
Worker(appContext, workerParams) {
override fun doWork(): Result {
// 分析堆快照
val doneEvent =
AndroidDebugHeapAnalyzer.runAnalysisBlocking(inputData.asEvent()) { event ->
// 发送分析进度事件
InternalLeakCanary.sendEvent(event)
}
// 发送分析完成事件
InternalLeakCanary.sendEvent(doneEvent)
return Result.success()
}
...
}
object BackgroundThreadHeapAnalyzer : EventListener {
internal val heapAnalyzerThreadHandler by lazy {
val handlerThread = HandlerThread("HeapAnalyzer")
handlerThread.start()
Handler(handlerThread.looper)
}
override fun onEvent(event: Event) {
if (event is HeapDump) {
heapAnalyzerThreadHandler.post {
// 分析堆快照
val doneEvent = AndroidDebugHeapAnalyzer.runAnalysisBlocking(event) { event ->
// 发送分析进度事件
InternalLeakCanary.sendEvent(event)
}
// 发送分析完成事件
InternalLeakCanary.sendEvent(doneEvent)
}
}
}
}
AndroidDebugHeapAnalyzer.runAnalysisBlocking
方法来分析堆快照的,并在分析过程中和分析完成后发送回调事件。Application.registerActivityLifecycleCallbacks(…)
接口监听 Activity.onCreate()事件,再通过 FragmentManager.registerFragmentLifecycleCallbacks(…)
接口监听 Fragment 的生命周期Hook
ViewModelStore的方式实现的mH.mCallback
回调,监听其中的STOP_SERVICE
消息来实现的WindowManagerGlobal
实现.hprof
文件.hprof
文件,获取泄漏对象,计算泄漏对象到 GC roots 的最短路径