栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

LeakCanary 分析:一只优雅的金丝雀

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

LeakCanary 分析:一只优雅的金丝雀

// 在 app 重写这个 bool 值

// 自己开发 SDK 时,这种配置方式学会了吗?

true

[](()监听泄漏的时机

===================================================================

Activity

没啥好说的,通过 registerActivityLifecycleCallbacks 监听 Activity 生命周期回调,在 onActivityDestroyed 时,objectWatcher.watch(activity, …)

Fragment、fragment.view

则是尝试从不同的 fragmentManager 加监听(emmm 策略模式)

  • O(奥利奥)以上 -> activity.fragmentManager (AndroidOFragmentDestroyWatcher.kt)

  • androidX -> activity.supportFragmentManager (AndroidXFragmentDestroyWatcher.kt)

  • support 包 -> activity.supportFragmentManager (AndroidSupportFragmentDestroyWatcher.kt)

调用 fragmentManager.registerFragmentLifecycleCallbacks 监听。

而上面用到的 activity 也是通过 registerActivityLifecycleCallbacks 的 onActivityCreated 拿到的

AndroidOFragmentDestroyWatcher.kt

override fun onFragmentViewDestroyed(

fm: FragmentManager,

fragment: Fragment

) {

val view = fragment.view

// 观察 view 是否回收

objectWatcher.watch(view,…)

}

override fun onFragmentDestroyed(

fm: FragmentManager,

fragment: Fragment

) {

// 观察 fragment 对象是否回收

objectWatcher.watch(fragment,…)

}

ViewModel

在前面讲到的 AndroidXFragmentDestroyWatcher.kt 里,还会额外监听

override fun onFragmentCreated(

fm: FragmentManager,

fragment: Fragment,

savedInstanceState: Bundle?

) {

ViewModelClearedWatcher.install(fragment, objectWatcher, configProvider)

}

install 的具体实现是在这个 fragment 的 ViewModelProvider 取一个 ViewModelClearedWatcher。这也是一个 ViewModel , 在它被回收时会回调 onCleared 方法将所有 ViewModel 加入观察

init {

// We could call ViewModelStore#keys with a package spy in androidx.lifecycle instead,

// however that was added in 2.1.0 and we support AndroidX first stable release. viewmodel-2.0.0

// does not have ViewModelStore#keys. All versions currently have the mMap field.

// 通过反射获取以这个 fragment 为 onwer 所有的 viewModel

viewModelMap = try {

val mMapField = ViewModelStore::class.java.getDeclaredField(“mMap”)

mMapField.isAcces 《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》无偿开源 徽信搜索公众号【编程进阶路】 sible = true

@Suppress(“UNCHECKED_CAST”)

mMapField[storeOwner.viewModelStore] as Map

}

}

override fun onCleared() {

if (viewModelMap != null && configProvider().watchViewModels) {

viewModelMap.values.forEach { viewModel ->

objectWatcher.watch( viewModel, … )

}

}

}

[](()检测一个对象是否泄露

======================================================================

一个 JVM 的基础知识:

public class WeakReference extends Reference {

public WeakReference(T referent, ReferenceQueue q) {

super(referent, q);

}

}

Java 中的 WeakReference 是弱引用类型,每当发生 GC 时,它所持有的对象如果没有被其他强引用所持有,那么它所引用的对象就会被回收,同时或者稍后的时间这个 WeakReference 会被入队到 ReferenceQueue. LeakCanary 中对内存泄露的检测正是基于这个原理。

实现要点:

  • 当一个 Object 需要被回收时,对应生成一个 key ,封装到自定义的 KeyedWeakReference 中,并且在 KeyedWeakReference 的构造器中传入自定义的 ReferenceQueue。

  • 同时将这个 KeyedWeakReference 缓存一份到 Map 中( ObjectWatcher.watchedObjects )

  • 最后主动触发 GC,遍历自定义 ReferenceQueue 中所有的记录,并根据获取的 KeyedWeakReference 里 key 的值,移除 Map 中相应的项。

「经过上面 3 步之后,还保留在 Map 中的就是:应当被 GC 回收,但是实际还保留在内存中的对象,也就是发生泄漏了的对象。」

我们来看下具体的代码:

ObjectWatcher.kt

fun watch(

watchedObject: Any,

description: String

) {

// 遍历 queue ,从 watchedObjects 移除相应项

removeWeaklyReachableObjects()

val key = UUID.randomUUID().toString()

val watchUptimeMillis = clock.uptimeMillis()

val reference =

KeyedWeakReference(watchedObject, key, description, watchUptimeMillis, queue)

}

watchedObjects[key] = reference

checkRetainedExecutor.execute {

// checkRetainedExecutor 通过 Handler.postDelayed 实现

// 默认延迟 5s , 去保留的对象里查看一下这个 key 是否还在

moveToRetained(key)

}

}

fun moveToRetained(key: String) {

removeWeaklyReachableObjects() // 再检查一遍是否已经回收

val retainedRef = watchedObjects[key]

if (retainedRef != null) {

retainedRef.retainedUptimeMillis = clock.uptimeMillis()

onObjectRetainedListeners.forEach { it.onObjectRetained() }

}

}

5S 后检查对象还在的话,调用 onObjectRetained 方法通知处理,调用到的是 InternalLeakCanary 的实现

override fun onObjectRetained() {

if (this::heapDumpTrigger.isInitialized) {

// 看名字就知道,这是触发 heap dump 相关的逻辑

heapDumpTrigger.onObjectRetained()

}

}

接着看 HeapDumpTrigger 里的相关调用:

onObjectRetained()

-> scheduleRetainedObjectCheck(…)

-> checkRetainedObjects(reason)

ivate fun checkRetainedObjects(reason: String) {

val config = configProvider()

var retainedReferenceCount = objectWatcher.retainedObjectCount

if (retainedReferenceCount > 0) {

// 执行一次 GC ,再来看还剩下多少对象未被回收

// 小细节:GC 之后还 sleep(100) 等回收的引用入队

gcTrigger.runGc()

retainedReferenceCount = objectWatcher.retainedObjectCount

}

// checkRetainedCount 以下两种情况 return true 不继续后面的流程

// 1. 若之前有显示有泄漏,且当前已经全部回收,显示无泄漏的通知

// 2. 存留的对象超过 5 个(默认,可配)且 (app 可见或不可见超过 5s),

// 延迟 2s 再进行检查(避免应用卡频繁卡)

// 判断 app 是否可见代码:VisibilityTracker.kt

if (checkRetainedCount(retainedReferenceCount, config.retainedVisibleThreshold)) return

if (!config.dumpHeapWhenDebugging && DebuggerControl.isDebuggerAttached) {

// 如果正在调试,可能影响检测结果,还是晚点再试吧

scheduleRetainedObjectCheck(

reason = “debugger is attached”,

rescheduling = true,

delayMillis = WAIT_FOR_DEBUG_MILLIS

)

return

}

val now = SystemClock.uptimeMillis()

val elapsedSinceLastDumpMillis = now - lastHeapDumpUptimeMillis

if (elapsedSinceLastDumpMillis < WAIT_BETWEEN_HEAP_DUMPS_MILLIS) {

// 一分钟之内才 dump 过,等离上次 dump 1分钟了再来吧

scheduleRetainedObjectCheck(

reason = “previous heap dump was ${xx}ms ago (< ${xx}ms)”,

rescheduling = true,

delayMillis = WAIT_BETWEEN_HEAP_DUMPS_MILLIS - elapsedSinceLastDumpMillis

)

return

}

// 终极操作

// 通过 Debug.dumpHprofData(filePath) dump heap

// objectWatcher.clearObjectsWatchedBefore(heapDumpUptimeMillis) 清除这次 dump 开始以前的所有引用

// HeapAnalyzerService.runAnalysis 通过一个 IntentService 去分析 heap

dumpHeap(retainedReferenceCount, retry = true)

}

HeapAnalyzerService 里调用的是 Shark 库对 heap 进行分析,分析的结果再返回到 DefaultOnHeapAnalyzedListener.onHeapAnalyzed 进行分析结果入库、发送通知消息。

Shark :Shark is the heap analyzer that powers LeakCanary 2. It’s a Kotlin standalone heap analysis library that runs at 「high speed」 with a 「low memory footprint」.

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/842157.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号