这里是基于Leakcanary 2.6 来查看
1. 使用
2.6 后使用很简单,直接在app gradle 下增加依赖
dependencies {
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.6'
}
这样就可以使用 Leakcanary,其原理为:注册一个ContentProvider 在ContentProvider 中 onCreate 方法中注册对应的检测程序。2.6 中这个ContentProvider 在这个包下面
2. 分析流程
进入AppWatcherInstaller中的onCreate方法
override fun onCreate(): Boolean {
//获取对应的Application
val application = context!!.applicationContext as Application
//初始化检测
AppWatcher.manualInstall(application)
return true
}
继续往下走,到AppWatcher 中的 manualInstall 方法中
@JvmOverloads
fun manualInstall(
application: Application,
retainedDelayMillis: Long = TimeUnit.SECONDS.toMillis(5),
watchersToInstall: List = appDefaultWatchers(application)
) {
//检测线程
checkMainThread()
//判断是否初始化
check(!isInstalled) {
"AppWatcher already installed"
}
//检测retainedDelayMillis
check(retainedDelayMillis >= 0) {
"retainedDelayMillis $retainedDelayMillis must be at least 0 ms"
}
this.retainedDelayMillis = retainedDelayMillis
//判断是否为Debuggable 构建,如果是,则开启日志
if (application.isDebuggableBuild) {
LogcatSharkLog.install()
}
// 初始化InternalLeakCanary
LeakCanaryDelegate.loadLeakCanary(application)
//注册监测程序
watchersToInstall.forEach {
it.install()
}
}
我们先来看InternalLeakCanary的初始化,点进去loadLeakCanary
@Suppress("UNCHECKED_CAST")
val loadLeakCanary by lazy {
try {
//这个我理解是通过反射的方式创建InternalLeakCanary对象,并调用invoke方法
val leakCanaryListener = Class.forName("leakcanary.internal.InternalLeakCanary")
leakCanaryListener.getDeclaredField("INSTANCE")
.get(null) as (Application) -> Unit
} catch (ignored: Throwable) {
NoLeakCanary
}
}
走到InternalLeakCanary 的invoke方法中
override fun invoke(application: Application) {
//给_application 复制
_application = application
//判断是否为Debug构建,如果不是,会抛出异常
checkRunningInDebuggableBuild()
//为AppWatcher.objectWatcher增加监听
AppWatcher.objectWatcher.addOnObjectRetainedListener(this)
//创建AndroidHeapDumper
val heapDumper = AndroidHeapDumper(application, createLeakDirectoryProvider(application))
//GC触发器
val gcTrigger = GcTrigger.Default
val configProvider = { LeakCanary.config }
//创建一个handler线程
val handlerThread = HandlerThread(LEAK_CANARY_THREAD_NAME)
handlerThread.start()
//创建子线程handler
val backgroundHandler = Handler(handlerThread.looper)
//创建HeapDump 触发器
heapDumpTrigger = HeapDumpTrigger(
application, backgroundHandler, AppWatcher.objectWatcher, gcTrigger, heapDumper,
configProvider
)
application.registerVisibilityListener { applicationVisible ->
this.applicationVisible = applicationVisible
heapDumpTrigger.onApplicationVisibilityChanged(applicationVisible)
}
registerResumedActivityListener(application)
addDynamicShortcut(application)
// We post so that the log happens after Application.onCreate()
mainHandler.post {
// https://github.com/square/leakcanary/issues/1981
// We post to a background handler because HeapDumpControl.iCanHasHeap() checks a shared pref
// which blocks until loaded and that creates a StrictMode violation.
backgroundHandler.post {
SharkLog.d {
when (val iCanHasHeap = HeapDumpControl.iCanHasHeap()) {
is Yup -> application.getString(R.string.leak_canary_heap_dump_enabled_text)
is Nope -> application.getString(
R.string.leak_canary_heap_dump_disabled_text, iCanHasHeap.reason()
)
}
}
}
}
}
上面主要还是创建一些对象,为之后使用做准备,接下来继续看监测器的install方法
@JvmOverloads
fun manualInstall(
application: Application,
retainedDelayMillis: Long = TimeUnit.SECONDS.toMillis(5),
watchersToInstall: List = appDefaultWatchers(application)
) {
//...
//install 方法
watchersToInstall.forEach {
it.install()
}
}
其中watchersToInstall通过appDefaultWatchers(application)来获取
fun appDefaultWatchers(
application: Application,
reachabilityWatcher: ReachabilityWatcher = objectWatcher
): List {
return listOf(
ActivityWatcher(application, reachabilityWatcher),
FragmentAndViewModelWatcher(application, reachabilityWatcher),
RootViewWatcher(reachabilityWatcher),
ServiceWatcher(reachabilityWatcher)
)
}
返回一个列表,通过名称可以知道有监测Activity,Fragment、RootView、Service的,这里我们看监测Activity 的,也就是ActivityWatcher.install()方法
class ActivityWatcher(
private val application: Application,
private val reachabilityWatcher: ReachabilityWatcher
) : InstallableWatcher {
private val lifecycleCallbacks =
object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
override fun onActivityDestroyed(activity: Activity) {
//当Activity 调用onDestroyed 方法是,判断回收
reachabilityWatcher.expectWeaklyReachable(
activity, "${activity::class.java.name} received Activity#onDestroy() callback"
)
}
}
override fun install() {
//通过Application 注册所有Activity 生命周期的监听
application.registerActivityLifecycleCallbacks(lifecycleCallbacks)
}
override fun uninstall() {
application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks)
}
}
很明显,通过Application 注册所有Activity生命周期的监听,当Activity调用onDestroyed方法时,判断该Activity是否回收。其中reachabilityWatcher时在ActivityWatcher构造方法中传过来,往上回溯可以知道为ObjectWatcher对象,所以继续到ObjectWatcher.expectWeaklyReachable()方法中
@Synchronized override fun expectWeaklyReachable(
watchedObject: Any,
description: String
) {
//判断是否可用,默认返回true
if (!isEnabled()) {
return
}
//移除watchedObjects这个map中并且存在弱引用queue中的数据
removeWeaklyReachableObjects()
//通过uuid 随机生成key
val key = UUID.randomUUID()
.toString()
//获取观察对象的时间
val watchUptimeMillis = clock.uptimeMillis()
//创建弱引用对象,注意最后一个参数把弱引用queue传过去了
val reference =
KeyedWeakReference(watchedObject, key, description, watchUptimeMillis, queue)
//如果时debug模式,打印观察对象信息
SharkLog.d {
"Watching " +
(if (watchedObject is Class<*>) watchedObject.toString() else "instance of ${watchedObject.javaClass.name}") +
(if (description.isNotEmpty()) " ($description)" else "") +
" with key $key"
}
//将弱引用对象保存到map中
watchedObjects[key] = reference
//执行检测
checkRetainedExecutor.execute {
moveToRetained(key)
}
}
上面代码主要是生成一个弱引用的对象,然后观察这个弱引用对象,继续看moveToRetained()方法
@Synchronized private fun moveToRetained(key: String) {
//又执行一遍一处,主要是一处watchedObjects这个map中并存在弱引用queue中的数据
removeWeaklyReachableObjects()
//通过key获取弱对象
val retainedRef = watchedObjects[key]
if (retainedRef != null) {
//设置该对象的retainedUptimeMillis
retainedRef.retainedUptimeMillis = clock.uptimeMillis()
//执行观察
onObjectRetainedListeners.forEach { it.onObjectRetained() }
}
}
其中onObjectRetainedListeners中的listener是在InternalLeakCanary.invoke方法中添加的
override fun invoke(application: Application) {
//...
//为AppWatcher.objectWatcher增加监听
AppWatcher.objectWatcher.addOnObjectRetainedListener(this)
//...
}
listener 是this 所以来到InternalLeakCanary.onObjectRetained()方法中
override fun onObjectRetained() = scheduleRetainedObjectCheck()
fun scheduleRetainedObjectCheck() {
//判断是否初始化
if (this::heapDumpTrigger.isInitialized) {
//执行检查
heapDumpTrigger.scheduleRetainedObjectCheck()
}
}
继续走到heapDumpTrigger.scheduleRetainedObjectCheck()方法中
fun scheduleRetainedObjectCheck(
delayMillis: Long = 0L
) {
//checkScheduledAt 默认为0
val checkCurrentlyScheduledAt = checkScheduledAt
if (checkCurrentlyScheduledAt > 0) {
return
}
//设置checkScheduledAt的值
checkScheduledAt = SystemClock.uptimeMillis() + delayMillis
//使用子线程handle 来执行,所以后面的方法是在子线程中执行
backgroundHandler.postDelayed({
checkScheduledAt = 0
// 检查对象
checkRetainedObjects()
}, delayMillis)
}
继续走,到checkRetainedObjects 方法中
private fun checkRetainedObjects() {
//做一些判断,我目前也不太理解这一个判断的用处
val iCanHasHeap = HeapDumpControl.iCanHasHeap()
val config = configProvider()
//根据判断,是否返回,现在假设没有进入这个if中
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
if (retainedReferenceCount > 0) {
gcTrigger.runGc()
retainedReferenceCount = objectWatcher.retainedObjectCount
}
val nopeReason = iCanHasHeap.reason()
val wouldDump = !checkRetainedCount(
retainedReferenceCount, config.retainedVisibleThreshold, nopeReason
)
if (wouldDump) {
val uppercaseReason = nopeReason[0].toUpperCase() + nopeReason.substring(1)
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
//如果没有被回收的对象个数大于0
if (retainedReferenceCount > 0) {
//执行一遍GC
gcTrigger.runGc()
//从新获取没有被回收对象的个数
retainedReferenceCount = objectWatcher.retainedObjectCount
}
//检查没有被回收对象的个数,如果少于5个,不会往下执行
if (checkRetainedCount(retainedReferenceCount, config.retainedVisibleThreshold)) return
//获取当前时间
val now = SystemClock.uptimeMillis()
//获取当前时间和上次执行时间的间隔
val elapsedSinceLastDumpMillis = now - lastHeapDumpUptimeMillis
//如果小于60_000L,这个应该是60秒...
if (elapsedSinceLastDumpMillis < WAIT_BETWEEN_HEAP_DUMPS_MILLIS) {
onRetainInstanceListener.onEvent(DumpHappenedRecently)
//发送通知
showRetainedCountNotification(
objectCount = retainedReferenceCount,
contentText = application.getString(R.string.leak_canary_notification_retained_dump_wait)
)
//延迟执行后面操作,也就是用60_000L - 当前间隔
scheduleRetainedObjectCheck(
delayMillis = WAIT_BETWEEN_HEAP_DUMPS_MILLIS - elapsedSinceLastDumpMillis
)
return
}
dismissRetainedCountNotification()
val visibility = if (applicationVisible) "visible" else "not visible"
//获取内存.hprof文件
dumpHeap(
retainedReferenceCount = retainedReferenceCount,
retry = true,
reason = "$retainedReferenceCount retained objects, app is $visibility"
)
}
到这里,就清楚Activity对象监测的流程:创建一个Activity 的弱引用对象,保存到map中,当Activity对象回收时,会将Activity的弱引用对象保存到弱引用的queue中,循环queue获取弱引用对象,移除map中的Activity 的弱引用对象, GC后还存在map中的Activity弱引用对象就是发生泄漏的对象。当这个对象超过5个,就会获取内存.hprof文件,检查对应的引用链。