LeakCanary源码分析

大家好,我是苍王。

以下是我这个系列的相关文章,有兴趣可以参考一下,可以给个喜欢或者关注我的文章。

[Android]如何做一个崩溃率少于千分之三噶应用app--章节列表


LeakCanary,金丝雀,在组件化Gank研发的时候,近来踩了一下坑,发现其内存泄露检测的思想非常精妙。

通读在这编文章你将会学会

1.知道LeakCanary对内存泄漏检测的原理

2.如何安装了应用后,隐藏和显示应用在launcher的显示

3.如何在主线程空闲时触发任务

4.如何检测顶层Activity的生命周期状态

5.除了凭借更改样式显示在TextView,是否还有其他方法改变TextView的显示样式?

6.如果判断进程是否在后台


一.配置

可以看到release debug所引用的leakcanary的工具是不同的。

工程目录

其中leakcanary-android/leakcanary-android-no-op是依赖于leakcanary-analyzer。

而leakcanary-analyzer依赖于leakcanary-watcher

工程使用的时候,需要在自定义的Application中使用

其还使用使用了StrictMode,这里有StrictMode详细介绍

二.源码分析

RefWatcher对象的安装

构建一个AndroidRefWatcherBuilder的对象

其是继承于RefWatcherBuilder对象的

设置后台的监听

其设置的监听者是用于分析泄露结果,和发送通知

在RefWatcherBuilder中设置excluedeRefs

这里创建泄露路径的记录建造者

其最终会build方法创建一个ExcludedRefs的对象

其参数用于记录泄露对象的路径参数

使用buildAndAInstall构建出RefWatcher对象

可以看出只支持4.0 ICS以上的

这里在RefWatcherBuilder利用建造者设计模式设置参数

关于具体这些参数分析

1.watchExecutor 是线程控制器,控制activity销毁后5s再去观察泄露情况

2.debuggerControl 控制debugger的,并未编写任何执行事件

3.gcTrigger 用来触发垃圾回收的,上面的线程控制器5s后观察有泄露,不算泄露,必须垃圾回收后,再去观察一次。所以最多会观察两次。第一次是5s后观察,第二次是5s后在垃圾回收后观察。

4.heapDumpListener hprof文件解释完后,会告诉这个监听者。这个监听者就会更新状态栏

5.excludedRefs 这玩意是做额外处理的,这里面定义了一些类,如果是这些类泄露了,不会提示的。例如我就是想我的Activity泄露,你别管我,那你可以把类名加到excludedRefs 中。

这里面还要打开显示泄露的Activity

这里面DisplayLeakActivity就是显示泄露的

我们看到AndroidManifest里面组件默认enabled =false的

而且这里可以看出HeapAnalyzerService分析内存泄露的后台是新的进程

这里使用PackageManager的setComponedtEnabledSettings开启。

正是这样,才能一开始未存在泄露时隐藏leakCanary的图标。

通过ActivityRefWatcher.install启动监听泄露

通过监听application.registerActivityLifecyleCallbacks的方法来监听周期


三.泄露过程分析

通过查看监听ActivityLifecycleCallbacks的回调监听destroy的方法。

启动对前台的Activity的检测

转化为对象去观看

可以看到此时创建一个持有Activity的弱引用

通过watchExcuter执行调用

这里面会是用的是AndroidWatchExcuter的对象

其时间是5秒

我们这里可以看到其会去持有主消息队列和创建出线程的消息队列

然后调用execute的方法来,无论waitForIdle或是postWaitForIdle,都是需要切换到主队列。

然后使用MessageQueue.IdleHandler可以用来在线程空闲的时候,指定一个操作,使用IdleHandler的好处在于可以不用指定一个将来时间,只要线程空闲了,就可以执行它指定的操作。

这里是使用Retryable,是有枚举状态的,如果是RETRY的返回状态,会重新执行。

AndroidWatchExcuter会调用ensureGone的方法

这里会需要试着移除弱引用,

判断队列里面是是否有对应Activity的弱引用对象

然后试着在retainedKeys集合里面试着移除

再次判断是否在集合中是否还包含引用对象,如果不包含就说明没有泄露

这里继续会走GC内存回收的流程

RunTime.getRunTime().gc()触发系统gc操作

enqueueReference通过强制限制100毫秒的时间给gc

System.runFinalization()是强制调用已经失去引用的对象的finalize方法

然后再进行弱引用对象移除

在判断如果依然没被移除,会调用heapDumper.dumpHeap的方法

这里泄露目录的定义

默认最多七个Dump文件

这里调用dumpHeap会创建文件.hrof的文件

newHeapDumpFile来创建.hrof文件

这里使用Debug.dumpHprofData这个类,是heap堆的快照,可以获知程序的哪些部分正在使用大部分的内存

然后使用heapdumpListener.analyze的方法分析堆内存

这里heapdumpListener使用的是AndroidRefWatcherBuilder里面的

进一步看到是使用HeapAnalyzerService.runAnalysis的方法

这里是启动一个其自身作为一个IntentService,

启动IntentService就会直接运行onHanldeIntent的方法,运行完就会释放回收掉Service

这里HeapAnalyzer会使用checkForLeak的方法来分析内存泄露结果

然后回调结果给上层的DisplayLeakService来处理结果

会调用findLeakTrace的侦测

这里建立检测泄露节点和返回泄露对象的详细信息。

这里最终会调用到squaredup的haha库,专用于分析Android的堆分析


我们看看将结果回调给Service的时候,会启动Service,然后将相应的result参数传递过去

我们看到IntentService,会调用onHeapAnalyzed的方法

DisplayLeakService被启动后读取相应的参数

可以看到设置了一些显示的参数后,会提示Notification和处理堆

LeackCanaryInternals发送Notification到状态栏

其通知的pendingIntent实际跳转到DisplayLeakActivity

这里提供了最终调用的方法给用户自己处理。

关于DisplayLeakActivity就是要将AnalysisResult展示出来。

其使用LIstView显示路径的时候,TextView的解析是使用html.forHtml来解析HTML文本拼接

我们可以看到其使用elementToHtmlString来拼接Html文本

具体Html文本的用法可以参考Android TextView使用HTML处理字体样式、显示图片等


然后回到一开始的Application装载LeakCanary,

其使用isInAnalyzerProcess分析应用函数

判断是否在后台进程

然后这里LeakCanary封装了一个非常好的判断是否后台进程的方法。

总结

显然leakCanary的设计非常精妙,可以非常容易检测的大部分内存泄漏了。

但是暂时发现的缺陷

1.如果首页的Activity一直不销毁(onDestroy)那么将一直无法检测到首页的调用栈的内存泄漏

2.无法检测Service产生的内存泄漏。


这节就到这里,

下一节将会更精彩,敬请期待!!!

群号是316556016,也可以扫码进群。我在这里期待你们的加入!!!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,818评论 25 707
  • 少腹逐瘀汤 药物组成 小茴香7粒(炒),干姜2分(炒),元胡1钱,没药2钱(研),当归3钱,川芎2钱,官桂1钱,赤...
    药生尘阅读 1,720评论 0 2
  • 谁事谁非
    少年宫开心阅读 180评论 0 0
  • 爱情如叶儿 曾经簇拥枝头 绿得夺目 不可一世 鲜花也因此而失色 爱情如叶儿 最后也飘离枝头 旋旋转转带着它的...
    萌宝春天阅读 227评论 0 0