当前位置: 首页 > news >正文

源码阅读 LeakCanary

LeakCanary源码分析

LeakCanary作为常用的内存泄漏分析工具,那是如何检测内存泄漏的呢?从注册入口分析,最新的LeakCanary 2.14,通过ContentProvider自动获取Context完成注册。

<providerandroid:name="leakcanary.internal.MainProcessAppWatcherInstaller"android:authorities="${applicationId}.leakcanary-installer"android:enabled="@bool/leak_canary_watcher_auto_install"android:exported="false" />

一、MainProcessAppWatcherInstaller

leakcanary.internal.MainProcessAppWatcherInstalleronCreate

internal class MainProcessAppWatcherInstaller : ContentProvider() {override fun onCreate(): Boolean {val application = context!!.applicationContext as ApplicationAppWatcher.manualInstall(application)return true}...
}

二、AppWatcher.manualInstall

manualInstall 中 完成 安装:

// leakcanary.internal.InternalLeakCanary 内部实现
LeakCanaryDelegate.loadLeakCanary(application)// 相关 Activity/Fragment 组件的 检测类,都初始化
watchersToInstall.forEach {it.install()
}
2.1 appDefaultWatchers

watchersToInstall 默认由 AppWatcher.appDefaultWatchers 创建 组件的内存检查对象。
他们都实现 InstallableWatcher 接口,实现 install()uninstall() 方法。

  fun appDefaultWatchers(application: Application,reachabilityWatcher: ReachabilityWatcher = objectWatcher): List<InstallableWatcher> {return listOf(ActivityWatcher(application, reachabilityWatcher),FragmentAndViewModelWatcher(application, reachabilityWatcher),RootViewWatcher(reachabilityWatcher),ServiceWatcher(reachabilityWatcher))}
2.2 ActivityWatcher - Activity的泄漏分析

Activity 利用生命周期函数 检测。

  1. 利用 Application.registerActivityLifecycleCallbacks() 监听
  2. onActivityDestroyed()时,调用 objectWatcher.expectWeaklyReachable() 进行 弱可达性分析

三、ObjectWatcher

ObjectWatcher 完成 内存检查对象的 弱引用创建 和 GC处理。
所有 Activity Fragment View 检测的 InstallableWatcher 都有 objectWatcher 成员,
需要检查泄漏时,来调用 expectWeaklyReachable 方法。

3.1 AppWatcher.objectWatcher 创建默认值
  val objectWatcher = ObjectWatcher(clock = { SystemClock.uptimeMillis() },checkRetainedExecutor = {check(isInstalled) {"AppWatcher not installed"}mainHandler.postDelayed(it, retainedDelayMillis)},isEnabled = { true })

解释: checkRetainedExecutor 作为 Executor 实现,延迟 5s 在 mainHandler 主线程完成。

3.2 expectWeaklyReachable 检查方法
  • KeyedWeakReference
  • watchedObjects[key]
  @Synchronized override fun expectWeaklyReachable(watchedObject: Any,description: String) {if (!isEnabled()) {return}removeWeaklyReachableObjects()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] = referencecheckRetainedExecutor.execute {moveToRetained(key)}}

相关字段说明:

  1. KeyedWeakReference 继承自 WeakReference,增加了 key 用于判断。
  2. watchedObjects 保存 UUIDkey的弱引用对象
  3. queueReferenceQueue, 用于GC回收时,弱引用会自动进入队列,也就是 未泄漏。
  4. checkRetainedExecutorExecutor,默认实现 延迟5s 执行。
3.3 removeWeaklyReachableObjects

queue中是 准备被回收的 Reference
循环 queue.poll() 获取,并移除 要回收 的引用对象。

  private fun removeWeaklyReachableObjects() {var ref: KeyedWeakReference?do {ref = queue.poll() as KeyedWeakReference?if (ref != null) {watchedObjects.remove(ref.key)}} while (ref != null)}
3.4 moveToRetained

这里会 触发 InternalLeakCanaryonObjectRetainer(),进一步 处理。

  @Synchronized private fun moveToRetained(key: String) {removeWeaklyReachableObjects()val retainedRef = watchedObjects[key]if (retainedRef != null) {retainedRef.retainedUptimeMillis = clock.uptimeMillis()onObjectRetainedListeners.forEach { it.onObjectRetained() }}}

四、InternalLeakCanary

回到 AppWatcher.manualInstall() 方法,对应:

LeakCanaryDelegate.loadLeakCanary(application)

会通过反射 创建 InternalLeakCanary对象, 并执行 InternalLeakCanary.invoke 方法,注册了上面的OnObjectRetainedListener监听器:

AppWatcher.objectWatcher.addOnObjectRetainedListener(this)
4.1 onObjectRetained

–> scheduleRetainedObjectCheck()
–> heapDumpTrigger.scheduleRetainedObjectCheck()
–> heapDumpTrigger.checkRetainedObjects()

checkRetainedObjects() 源码:

    ...var retainedReferenceCount = objectWatcher.retainedObjectCountif (retainedReferenceCount > 0) {gcTrigger.runGc()retainedReferenceCount = objectWatcher.retainedObjectCount}...dumpHeap(retainedReferenceCount = retainedReferenceCount,retry = true,reason = "$retainedReferenceCount retained objects, app is $visibility")

这里关键地方:

  1. gcTrigger.runGc() 运行GC,检测泄漏对象数量。
  2. heapDump() 方法,保存栈信息,本质是 Android的 Debug.dumpHprofData()

看源码:HeapDumpTrigger.kt

4.2 GcTrigger

通过 Runtime.getRuntime().gc() 进行 GC 操作。

  object Default : GcTrigger {override fun runGc() {Runtime.getRuntime().gc()enqueueReferences()System.runFinalization()}...}

源码:GcTrigger.kt

4.3 AndroidDebugHeapDumper

利用 Android Api Debug.dumpHprofData(path) 获取栈信息:

object AndroidDebugHeapDumper : HeapDumper {override fun dumpHeap(heapDumpFile: File) {Debug.dumpHprofData(heapDumpFile.absolutePath)}
}

文档

  • LeakCanary v2.14 | Github
  • LeakCanary Getting Started
  • 探索Android开源框架 - 7. LeakCanary使用及源码解析
  • LeakCanary2.6抽丝剥茧-源码分析
  • LeakCanary2源码解析
http://www.dtcms.com/a/465428.html

相关文章:

  • Java 网络流式编程
  • java后端工程师进修ing(研一版‖day51)
  • JavaScript Promise 详解:从入门到精通
  • 中山建设银行招聘网站网站设计的评估
  • 深圳制作网站培训机构自己做的网站打开超慢
  • MySQL数据库优化实战提升查询性能的五大核心策略
  • libboost_system-mt-x64.so.1.76.0 和libboost_system-mt-d-x64.so.1.76.0 区别
  • 【11408学习记录】考研数学核心突破:线性代数特征值与特征向量详解+英语长难句精析
  • 深入剖析:基于epoll与主从Reactor模型的高性能服务器设计与实现
  • 非小细胞肺癌与肿瘤相关巨噬细胞:新的治疗策略
  • React Native:发现默认参数children【特殊的prop】
  • Flink进阶:从“会用”到“用明白”的踩坑与实战总结
  • 最专业的礼品网站实例网站优化费用怎么做会计分录
  • 苍穹外卖-工作台实现、Apache POI、导出Excel报表
  • 自定义类型:联合与枚举
  • Java9
  • 基于Spring Boot + Vue 3的乡村振兴综合服务平台
  • Java-145 深入浅出 MongoDB 基本操作详解:数据库查看、切换、创建集合与删除完整教程
  • disable-devtool 网络安全 禁止打开控制台
  • TCP协议的可靠性保障
  • ktv支付订房网站模板商业策划书范文6篇
  • 十一、OpenCV中图形的绘制
  • 用户中心网站设计北京社保网址
  • 安卓13_ROM修改定制化-----如何给安卓手机里安装或者内置数字证书文件 cer类型的证书文件如何转换为可内置文件
  • 仿mudou——Connection模块(连接管理)
  • vue3 + el-upload组件集成阿里云视频点播从本地上传至点播存储
  • 外贸网站是用什么软件做的法制教育网站
  • c/c++字符串比较
  • 国外建站公司上海企业自助建站系统
  • AI 生产工艺参数优化:中小型制造企业用 “智能调参“ 提升产品合格率与生产效率