你们好,我是苍王。
html
如下是我这个系列的相关文章,有兴趣能够参考一下,能够给个喜欢或者关注个人文章。android
[Android]如何作一个崩溃率少于千分之三噶应用app--章节列表git
LeakCanary,金丝雀,在组件化Gank研发的时候,近来踩了一下坑,发现其内存泄露检测的思想很是精妙。github
能够看到release debug所引用的leakcanary的工具是不一样的。面试
工程目录设计模式
其中leakcanary-android/leakcanary-android-no-op是依赖于leakcanary-analyzer。app
而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,也能够扫码进群。我在这里期待大家的加入!!!