文章目录
简介
本篇LeakCanary的源码分析,基于2.7版本
- 从2.x版本全部使用Kotlin进行编码
- 可以在一次分析中检测到多个内存泄漏
当应用进入后台,或者在前台泄漏到达5次时,将heap数据进行存储
- 对内存泄漏进行分组
- 按照泄漏相似原因在UI中分组
- 使用多屏样式,针对多组和单组列表样式进行查看
- 对泄漏原因及trace日志进行高光展示
- 泄漏能够分享到StackOverFlow
- 引入了新库LeakSentry
1.可以用来检测何时发生内存泄漏并触发LeakCanary
2.可以在生产环境中单独使用
- 内存泄漏分析库由haha替换为了shark库
1.内存占用减少了90%,速度提升了6倍
2.与应用程序在同一进程中,使用低优先级线程进行工作
3.不再依赖 Perflib 和 TroveJ。对 Okio 的新依赖
- 侵入性降低,只需依赖即可使用
- 提供了更简单的配置选项
- 从Support库迁移到Android X
1、LeakCanary的启动及初始化
- 新版本的LeakCanary只需要添加依赖导入即可使用,不需要手动调用install()来实现注册。
- 原理在于其利用了ContentProvider的onCreate()方法先于Applicaiton的onCreate()方法执行。
源码查看
1.1 leakcanary-object-watcher-android AndroidManifest.xml中定义contentProvider
<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>
1.2 AppWatcherInstaller.kt 中onCreate()
internal sealed class AppWatcherInstaller : ContentProvider() {
.... 省略非关键代码
override fun onCreate(): Boolean {
val application = context!!.applicationContext as Application
// 加载LeakCanary
AppWatcher.manualInstall(application)
return true
}
我们看到在AppWatcherInstaller的onCreate()方法中,首先获取了Application然后手动调用AppWatcher.manualInstall(application)来加载LeakCanary
- AppWatcher.manualInstall(application)
@JvmOverloads
fun manualInstall(
application: Application,
// 默认保持5s延迟检测
retainedDelayMillis: Long = TimeUnit.SECONDS.toMillis(5),
// watchers 列表默认为appDefaultWatchers
watchersToInstall: List<InstallableWatcher> = appDefaultWatchers(application)
) {
// 主线程判断
checkMainThread()
// 防止重复加载
if (isInstalled) {
throw IllegalStateException(
"AppWatcher already installed, see exception cause for prior install call", installCause
)
}
// 延时时间检测,必须大于0才可以,否则抛出异常
check(retainedDelayMillis >= 0) {
"retainedDelayMillis $retainedDelayMillis must be at least 0 ms"
}
installCause = RuntimeException("manualInstall() first called here")
// 缓存延迟检测时间
this.retainedDelayMillis = retainedDelayMillis
// LogcatSharkLog只有在debug状态下才会打印
if (application.isDebuggableBuild) {
LogcatSharkLog.install()
}
// Requires AppWatcher.objectWatcher to be set
// 获取InternalLeakCanary实例加载leakCanary
LeakCanaryDelegate.loadLeakCanary(application)
// 循环加载watcher
watchersToInstall.forEach {
it.install()
}
}
- appDefaultWatchers
fun appDefaultWatchers(
application: Application,
// 默认为objectWatcher
reachabilityWatcher: ReachabilityWatcher = objectWatcher
): List<InstallableWatcher> {
return listOf(
ActivityWatcher(application, reachabilityWatcher),
FragmentAndViewModelWatcher(application, reachabilityWatcher),
RootViewWatcher(reachabilityWatcher),
ServiceWatcher(reachabilityWatcher)
)
reachabilityWatcher默认值为objectWatcher
默认watchers:
1.ActivityWatcher
2.FragmentAndViewModelWatcher
3.RootViewWatcher
4.ServiceWatcher
在manualInstall方法中做了以下几件事情:
- 设置默认5s的延迟检测时间
- 设置默认安装的内存监视器安装list
- 非主线程运行判断拦截
- leakCanary重复加载判断拦截
- 延迟检测时间检测,不能小于0s
- 缓存延迟检测时间
- 判断是否是debug状态选择性安装LogcatSharkLog
- 获取InternalLeakCanary实例并加载leakCanary
- 循环加载watchers列表中内存监视器
2、内存泄漏检测怎么实现的
2.1 ActivityWatcher
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监视activity
reachabilityWatcher.expectWeaklyReachable(
activity, "${activity::class.java.name} received Activity#onDestroy() callback"
)
}
}
override fun install() {
// 注册应用activity生命周期回调
application.registerActivityLifecycleCallbacks(lifecycleCallbacks)
}
override fun uninstall() {
// 反注册activity生命周期回调
application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks)
}
}
通过install方法注册了activity的生命周期回调,并在onActivityDestroyed()方法中通过ObjectWatcher对activity进行监视
- ObjectWatcher.kt 中 expectWeaklyReachable方法
@Synchronized override fun expectWeaklyReachable(
watchedObject: Any,
description: String
) {
if (!isEnabled()) {
return
}
// 2.1.1 移除弱引用可达Activity对象
removeWeaklyReachableObjects()
val key = UUID.randomUUID()
.toString()
val watchUptimeMillis = clock.uptimeMillis()
// 2.1.2 根据activity键创建弱引用,并绑定到引用队列中
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"
}
// 将引用以键值形式存储在被监视的对象map集合中
watchedObjects[key] = reference
// 通过线程池来启动任务
checkRetainedExecutor.execute {
// 2.1.3 获取不能回收的activity
moveToRetained(key)
}
}
- 2.1.1 ObjectWatcher.kt 中 removeWeaklyReachableObjects
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.
// 在GC和finalization之前,弱应用对象会变为weakly reachable
var ref: KeyedWeakReference?
// 移除处于弱引用状态下的对象,留下不能被GC回收的对象
do {
ref = queue.poll() as KeyedWeakReference?
if (ref != null) {
watchedObjects.remove(ref.key)
}
} while (ref != null)
}
- 2.1.2 ObjectWatcher.kt 中 KeyedWeakReference(watchedObject, key, description, watchUptimeMillis, queue)
// 通过传入的参数构建WeakReference
class KeyedWeakReference(
referent: Any,
val key: String,
val description: String,
val watchUptimeMillis: Long,
referenceQueue: ReferenceQueue<Any>
) : WeakReference<Any>(
referent, referenceQueue
)
- 2.1.3 ObjectWatcher.kt 中 moveToRetained(key)
@Synchronized private fun moveToRetained(key: String) {
// 移除不发生内存泄漏activity
removeWeaklyReachableObjects()
val retainedRef = watchedObjects[key]
if (retainedRef != null) {
// 保存泄漏对象时间戳
retainedRef.retainedUptimeMillis = clock.uptimeMillis()
// 通知InternalLeakCanary发生内存泄漏
onObjectRetainedListeners.forEach {
// 2.1.4
it.onObjectRetained()
}
}
}
- 2.1.4 InternalLeakCanary.kt 中onObjectRetained
override fun onObjectRetained() = scheduleRetainedObjectCheck()
fun scheduleRetainedObjectCheck() {
if (this::heapDumpTrigger.isInitialized) {
// 2.1.5 通知heapDumpTrigger定时检查持有对象
heapDumpTrigger.scheduleRetainedObjectCheck()
}
}
- 2.1.5 HeapDumpTrigger.kt 中scheduleRetainedObjectCheck
fun scheduleRetainedObjectCheck(
delayMillis: Long = 0L
) {
val checkCurrentlyScheduledAt = checkScheduledAt
if (checkCurrentlyScheduledAt > 0) {
return
}
checkScheduledAt = SystemClock.uptimeMillis() + delayMillis
// 通过handler发送延迟检测对象任务
backgroundHandler.postDelayed({
checkScheduledAt = 0
// 2.1.6 检测持有对象
checkRetainedObjects()
}, delayMillis)
}
- 2.1.6 HeapDumpTrigger.kt 中 checkRetainedObjects()
private fun checkRetainedObjects() {
// 堆存储判断
val iCanHasHeap = HeapDumpControl.iCanHasHeap()
// 获取provider配置
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
// 获取持有对象引用数量
if (retainedReferenceCount > 0) {
// 2.1.7 手动调用GC
gcTrigger.runGc()
// 对持有对象数进行赋值
retainedReferenceCount = objectWatcher.retainedObjectCount
}
val nopeReason = iCanHasHeap.reason()
// 2.1.8 检测是否需要进行堆存储trace
val wouldDump = !checkRetainedCount(
retainedReferenceCount, config.retainedVisibleThreshold, nopeReason
)
if (wouldDump) {
val uppercaseReason = nopeReason[0].toUpperCase() + nopeReason.substring(1)
// 进行持有实例对象回调
onRetainInstanceListener.onEvent(DumpingDisabled(uppercaseReason))
// 2.1.9 显示持有对象通知
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
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
}
// 2.1.10 关闭持有对象数量通知
dismissRetainedCountNotification()
val visibility = if (applicationVisible) "visible" else "not visible"
// 2.1.11 堆转储
dumpHeap(
retainedReferenceCount = retainedReferenceCount,
retry = true,
reason = "$retainedReferenceCount retained objects, app is $visibility"
)
}
- 2.1.7 GcTrigger.kt 中runGc()
interface GcTrigger {
object Default : GcTrigger {
override fun runGc() {
// 调用Runtime系统的gc方法
Runtime.getRuntime()
.gc(
// 延迟100ms
enqueueReferences()
System.runFinalization()
}
private fun enqueueReferences() {
try {
Thread.sleep(100)
} catch (e: InterruptedException) {
throw AssertionError()
}
}
}
}
- 2.1.8 HeapDumpTrigger.kt 中checkRetainedCount
private fun checkRetainedCount(
retainedKeysCount: Int,
retainedVisibleThreshold: Int,
nopeReason: String? = null
): Boolean {
// 检测持有的对象数量是否发生了变更
val countChanged = lastDisplayedRetainedObjectCount != retainedKeysCount
lastDisplayedRetainedObjectCount = retainedKeysCount
// 没有内存泄露的对象
if (retainedKeysCount == 0) {
if (countChanged) {
SharkLog.d { "All retained objects have been garbage collected" }
onRetainInstanceListener.onEvent(NoMoreObjects)
// 显示没有持有对象通知
showNoMoreRetainedObjectNotification()
}
return true
}
... 省略非关键代码
// 持有的对象数小于阀值时(默认阀值为5)
if (retainedKeysCount < retainedVisibleThreshold) {
if (applicationVisible || applicationInvisibleLessThanWatchPeriod) {
if (countChanged) {
onRetainInstanceListener.onEvent(BelowThreshold(retainedKeysCount))
}
// 显示持有对象通知
showRetainedCountNotification(
objectCount = retainedKeysCount,
contentText = application.getString(
R.string.leak_canary_notification_retained_visible, retainedVisibleThreshold
)
)
// 延迟2s定时检测持有的对象
scheduleRetainedObjectCheck(
delayMillis = WAIT_FOR_OBJECT_THRESHOLD_MILLIS
)
return true
}
}
return false
}
- 检查对象持有数量是否发生变更
- 无持有对象时显示没有持有对象通知
- 持有对象数小于默认阀值时,发送持有对象通知,并定时间隔2s检测持有对象数量
- 2.1.9 HeapDumpTrigger.kt 中showRetainedCountNotification
private fun showRetainedCountNotification(
objectCount: Int,
contentText: String
) {
// 移除dismiss通知回调 backgroundHandler.removeCallbacks(scheduleDismissRetainedCountNotification)
if (!Notifications.canShowNotification) {
return
}
// 通过调用系统通知方法发送通知
@Suppress("DEPRECATION")
val builder = Notification.Builder(application)
.setContentTitle(
application.getString(R.string.leak_canary_notification_retained_title, objectCount)
)
.setContentText(contentText)
.setAutoCancel(true)
.setContentIntent(NotificationReceiver.pendingIntent(application, DUMP_HEAP))
val notification =
Notifications.buildNotification(application, builder, LEAKCANARY_LOW)
notificationManager.notify(R.id.leak_canary_notification_retained_objects, notification)
}
- 2.1.10 HeapDumpTrigger.kt 中dismissRetainedCountNotification()
private fun dismissRetainedCountNotification() {
// 移除handler回调 backgroundHandler.removeCallbacks(scheduleDismissRetainedCountNotification)
// 调用系统通知取消方法
notificationManager.cancel(R.id.leak_canary_notification_retained_objects)
}
- 2.1.11 HeapDumpTrigger.kt 中dumpHeap
private fun dumpHeap(
retainedReferenceCount: Int,
retry: Boolean,
reason: String
) {
saveResourceIdNamesToMemory()
val heapDumpUptimeMillis = SystemClock.uptimeMillis()
KeyedWeakReference.heapDumpUptimeMillis = heapDumpUptimeMillis
// 2.1.12 查看堆转储结果
when (val heapDumpResult = heapDumper.dumpHeap()) {
// 无堆转储
is NoHeapDump -> {
if (retry) {
SharkLog.d { "Failed to dump heap, will retry in $WAIT_AFTER_DUMP_FAILED_MILLIS ms" }
scheduleRetainedObjectCheck(
delayMillis = WAIT_AFTER_DUMP_FAILED_MILLIS
)
} else {
SharkLog.d { "Failed to dump heap, will not automatically retry" }
}
// 显示堆持有的通知数
showRetainedCountNotification(
objectCount = retainedReferenceCount,
contentText = application.getString(
R.string.leak_canary_notification_retained_dump_failed
)
)
}
// 存在堆转储文件
is HeapDump -> {
lastDisplayedRetainedObjectCount = 0
lastHeapDumpUptimeMillis = SystemClock.uptimeMillis()
objectWatcher.clearObjectsWatchedBefore(heapDumpUptimeMillis)
// 通过开启服务来分析堆转储文件
HeapAnalyzerService.runAnalysis(
context = application,
heapDumpFile = heapDumpResult.file,
heapDumpDurationMillis = heapDumpResult.durationMillis,
heapDumpReason = reason
)
}
}
}
通过heapDumper来进行堆转储文件进行检查,如果不存在显示通知,如果存在开启服务对存在的文件进行分析
- 2.1.12 HeapDumper.kt 中dumpHeap()
internal interface HeapDumper {
/**
* @return a [File] referencing the dumped heap, or [.RETRY_LATER] if the heap could
* not be dumped.
*/
fun dumpHeap(): DumpHeapResult
}
我们看到HeapDumper是一个接口,那直接查看其实现类来看下具体实现
- 2.1.13 AndroidHeapDumper.kt 中dumpHeap()
internal class AndroidHeapDumper(
context: Context,
private val leakDirectoryProvider: LeakDirectoryProvider
) : HeapDumper {
private val context: Context = context.applicationContext
override fun dumpHeap(): DumpHeapResult {
// 2.1.14 查询heap文件是否为空,如果为不为空直接使用之前的文件进行存储,否则返回NoHeapDump状态
val heapDumpFile = leakDirectoryProvider.newHeapDumpFile() ?: return NoHeapDump
val waitingForToast = FutureResult<Toast?>()
showToast(waitingForToast)
// 等待5s显示toast
if (!waitingForToast.wait(5, SECONDS)) {
SharkLog.d { "Did not dump heap, too much time waiting for Toast." }
return NoHeapDump
}
// 显示通知
val notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (Notifications.canShowNotification) {
val dumpingHeap = context.getString(R.string.leak_canary_notification_dumping)
val builder = Notification.Builder(context)
.setContentTitle(dumpingHeap)
val notification = Notifications.buildNotification(context, builder, LEAKCANARY_LOW)
notificationManager.notify(R.id.leak_canary_notification_dumping_heap, notification)
}
val toast = waitingForToast.get()
return try {
val durationMillis = measureDurationMillis {
// 2.1.15 生成heap文件
Debug.dumpHprofData(heapDumpFile.absolutePath)
}
if (heapDumpFile.length() == 0L) {
SharkLog.d { "Dumped heap file is 0 byte length" }
NoHeapDump
} else {
HeapDump(file = heapDumpFile, durationMillis = durationMillis)
}
} catch (e: Exception) {
SharkLog.d(e) { "Could not dump heap" }
// Abort heap dump
NoHeapDump
} finally {
cancelToast(toast)
notificationManager.cancel(R.id.leak_canary_notification_dumping_heap)
}
}
- 2.1.14 LeakDirectoryProvider 中newHeapDumpFile方法
fun newHeapDumpFile(): File? {
cleanupOldHeapDumps()
var storageDirectory = externalStorageDirectory()
// 如果文件夹不满足存储条件
if (!directoryWritableAfterMkdirs(storageDirectory)) {
// 无权限检查写权限
if (!hasStoragePermission()) {
if (requestExternalStoragePermission()) {
SharkLog.d { "WRITE_EXTERNAL_STORAGE permission not granted, requesting" }
requestWritePermissionNotification()
} else {
SharkLog.d { "WRITE_EXTERNAL_STORAGE permission not granted, ignoring" }
}
} else {
val state = Environment.getExternalStorageState()
// 无存储卡 打印日志
if (Environment.MEDIA_MOUNTED != state) {
SharkLog.d { "External storage not mounted, state: $state" }
} else {
SharkLog.d {
"Could not create heap dump directory in external storage: [${storageDirectory.absolutePath}]"
}
}
}
// Fallback to app storage.
storageDirectory = appStorageDirectory()
// 返回null
if (!directoryWritableAfterMkdirs(storageDirectory)) {
SharkLog.d {
"Could not create heap dump directory in app storage: [${storageDirectory.absolutePath}]"
}
return null
}
}
// 直接heap返回文件
val fileName = SimpleDateFormat("yyyy-MM-dd_HH-mm-ss_SSS'.hprof'", Locale.US).format(Date())
return File(storageDirectory, fileName)
}
- 2.1.15 Debug.java 中Debug.dumpHprofData
// 调用系统sdk提供的方法生成heap文件
public static void dumpHprofData(String fileName) throws IOException {
SDk.dumpHprofData(fileName);
}
2.2 FragmentAndViewModelWatcher
- 2.2.1 FragmentAndViewModelWatcher.kt 中install方法
override fun install() {
application.registerActivityLifecycleCallbacks(lifecycleCallbacks)
}
在install方法中注册Activity生命周期回调,因为Fragment是依附于Activity来添加,所以此处注册Activity生命周期回调
- 2.2.2 FragmentAndViewModelWatcher.kt 中lifecycleCallbacks回调
private val lifecycleCallbacks =
object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
// 注册onActivityCreate生命周期回调
override fun onActivityCreated(
activity: Activity,
savedInstanceState: Bundle?
) {
// 2.2.3 遍历fragmentDestroyWatchers
for (watcher in fragmentDestroyWatchers) {
// watcher监测activity
watcher(activity)
}
}
}
- watch(activity) 实际是对应kotlin中Functions.kt文件的Function1接口,P1为Activity,R为Unit即为Java的void
package kotlin.jvm.functions
interface Function1<in P1, out R> : kotlin.Function<R> {
fun invoke(p1: P1): R
}
也就是说,watch(activity)最终调用的是watcher中的invoke(Activity)方法
- 2.2.3 FragmentAndViewModelWatcher.kt 中fragmentDestroyWatchers
private val fragmentDestroyWatchers: List<(Activity) -> Unit> = run {
val fragmentDestroyWatchers = mutableListOf<(Activity) -> Unit>()
// SDK版本大于Android O(26 Android8.0)
if (SDK_INT >= O) {
fragmentDestroyWatchers.add(
// 添加Android O fragmentDestoryWatcher
// Android O 版本DestoryWatcher
AndroidOFragmentDestroyWatcher(reachabilityWatcher)
)
}
// 2.2.4 针对androidX 版本fragment
getWatcherIfAvailable(
ANDROIDX_FRAGMENT_CLASS_NAME,
ANDROIDX_FRAGMENT_DESTROY_WATCHER_CLASS_NAME,
reachabilityWatcher
)?.let {
// 2.4.5 添加观察者
fragmentDestroyWatchers.add(it)
}
// 针对support 版本fragment
getWatcherIfAvailable(
ANDROID_SUPPORT_FRAGMENT_CLASS_NAME,
ANDROID_SUPPORT_FRAGMENT_DESTROY_WATCHER_CLASS_NAME,
reachabilityWatcher
)?.let {
// 添加观察者
fragmentDestroyWatchers.add(it)
}
// 返回watcher集合
fragmentDestroyWatchers
}
- 2.2.4 FragmentAndViewModelWatcher.kt 中getWatcherIfAvailable
private fun getWatcherIfAvailable(
fragmentClassName: String,
watcherClassName: String,
reachabilityWatcher: ReachabilityWatcher
): ((Activity) -> Unit)? {
// 通过类名获取类对象
return if (classAvailable(fragmentClassName) &&
classAvailable(watcherClassName)
) {
val watcherConstructor =
// 获取构造方法Class.forName(watcherClassName).getDeclaredConstructor(ReachabilityWatcher::class.java)
// 通过构造方法实例化activity
@Suppress("UNCHECKED_CAST")
watcherConstructor.newInstance(reachabilityWatcher) as (Activity) -> Unit
} else {
null
}
}
- 2.2.5 AndroidOFragmentDestroyWatcher.kt
@SuppressLint("NewApi")
internal class AndroidOFragmentDestroyWatcher(
private val reachabilityWatcher: ReachabilityWatcher
) : (Activity) -> Unit {
private val fragmentLifecycleCallbacks = object : FragmentManager.FragmentLifecycleCallbacks() {
// 注册onFragmentViewDestoryed监听
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)"
)
}
}
// 注册onFragmentDestroyed监听
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)
}
}
通过前面2.1中我们分析ActivityWatcher我们看到AndroidOFragmentDestroyWatcher中实现与ActivityWatcher基本相似,都是通过ObjectWatcher.kt 中 expectWeaklyReachable方法来实现,这里不再赘述
2.3 RootViewWatcher
- 2.3.1 RootViewWatcher.kt 中install() 方法
override fun install() {
// 2.3.1 添加listener 到Curtains中
Curtains.onRootViewsChangedListeners += listener
}
我们看到install方法将listener添加到了Curtains的OnRootViewsChangedListener列表中,而Curtains中onRootViewsChangedListeners记录了root views的数量并在数量发生变更后调用onRootViewsChanged方法
- 2.3.1 RootViewWatcher.kt 中listener
private val listener = OnRootViewAddedListener { rootView ->
// 根据windowType 类型不同判断trackDetached状态
val trackDetached = when(rootView.windowType) {
PHONE_WINDOW -> {
when (rootView.phoneWindow?.callback?.wrappedCallback) {
// Activities are already tracked by ActivityWatcher
is Activity -> false
is Dialog -> rootView.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, UNKNOWN -> true
}
// trackeDetached状态为true,添加rootView的状态变更监听
if (trackDetached) {
rootView.addOnAttachStateChangeListener(object : OnAttachStateChangeListener {
// 开启子线程检查rootView引用状态检测是否存在内存泄漏
val watchDetachedView = Runnable {
// 这里也是通过objectWatcher进行监视,前面2.1已经分析,同上
reachabilityWatcher.expectWeaklyReachable(
rootView, "${rootView::class.java.name} received View#onDetachedFromWindow() callback"
)
}
// 根据生命周期回调通过mainHandler处理view事件
override fun onViewAttachedToWindow(v: View) {
mainHandler.removeCallbacks(watchDetachedView)
}
override fun onViewDetachedFromWindow(v: View) {
mainHandler.post(watchDetachedView)
}
})
}
}
- 根据rootView的windowType判断是否需要进行track跟踪
- 针对需要跟踪的rootView类型开启子线程检查其引用状态,判断是否存在内存泄漏
- 针对需要跟踪的rootView生命周期回调,通过mainHandler进行消息传递
2.4 ServiceWatcher
- 2.4.1 ServiceWatcher.kt 中install()方法
override fun install() {
// 主线程检测
checkMainThread()
// 非空抛出异常
check(uninstallActivityThreadHandlerCallback == null) {
"ServiceWatcher already installed"
}
check(uninstallActivityManager == null) {
"ServiceWatcher already installed"
}
try {
// 转换Activity线程Handler的callback
swapActivityThreadHandlerCallback { mCallback ->
uninstallActivityThreadHandlerCallback = {
swapActivityThreadHandlerCallback {
mCallback
}
}
Handler.Callback { msg ->
// 监听what值
if (msg.what == STOP_SERVICE) {
val key = msg.obj as IBinder
activityThreadServices[key]?.let {
// 2.4.2 预关闭service
onServicePreDestroy(key, it)
}
}
// 通过callback处理关闭服务消息
mCallback?.handleMessage(msg) ?: false
}
}
swapActivityManager { activityManagerInterface, activityManagerInstance ->
uninstallActivityManager = {
swapActivityManager { _, _ ->
activityManagerInstance
}
}
// 通过动态代理来获取activityManagerInterface参数
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)) {
// 2.4.3 调用serviceDestory关闭回调
onServiceDestroyed(token)
}
}
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" }
}
}
- 2.4.2 ServiceWatcher.kt 中onServicePreDestroy()
private fun onServicePreDestroy(
token: IBinder,
service: Service
) {
// 将service变为弱引用状态,便于GC
servicesToBeDestroyed[token] = WeakReference(service)
}
- 2.4.3 ServiceWatcher.kt 中onServiceDestroyed(token)
private fun onServiceDestroyed(token: IBinder) {
// 将service从servicesToBeDestroyed集合中移除
servicesToBeDestroyed.remove(token)?.also { serviceWeakReference ->
serviceWeakReference.get()?.let { service ->
// 通过reachabilityWatcher监视内存泄漏的对象,与2.1相同,不再赘述
reachabilityWatcher.expectWeaklyReachable(
service, "${service::class.java.name} received Service#onDestroy() callback"
)
}
}
}