版权声明:本文为原创文章,未经允许不得转载。
LeakCanary是一个安卓的性能统计工具,想必大家都有使用,工具出自大名鼎鼎的Jake Wharton大神,截止目前为止其在GitHub的star数目已达到15.4k,可见其受到的欢迎程度,下面我将通过UML类图以及流程图,最后配上部分源码对源码进行解析。
一、LeakCanary流程图
LeakCanary的代码风格主要使用的是Builder建造者模式,其主要的思想也就是监听Activity的销毁,然后进行性能统计,目前其仅支持SDK14版本及以上,不过已覆盖绝大多数手机。其流程图很简单,如下:
LeakCanary流程图.png如图可见,直到执行buildAndInstall()之前都是搜集所需属性,然后通过buildAndInstall()方法执行安卓统计。这里仅仅是让大家有个整体的执行流程的了解。
二、LeakCanary类图
LeakCanary类图.png如开头所说,LeakCanary的代码风格以Builder建造者为主,在该类图中可见建造者为AndroidRefWatcherBuilder,其继承于父类RefWatcherBuilder。
三、LeakCanary源码执行流程
AndroidRefWatcherBuilder作为整个库的核心建造者,其属性如下:
private ExcludedRefs excludedRefs;
private Listener heapDumpListener;
private DebuggerControl debuggerControl;
private HeapDumper heapDumper;
private WatchExecutor watchExecutor;
private GcTrigger gcTrigger;
下面再来看下LeakCanary执行的入口方法install源码:
public staticRefWatcher install(Application application) {
return((AndroidRefWatcherBuilder)refWatcher(application)
.listenerServiceClass(DisplayLeakService.class)
.excludedRefs(AndroidExcludedRefs.createAppDefaults().build()))
.buildAndInstall();
}
继续跟进listenerServiceClass方法:
public AndroidRefWatcherBuilder listenerServiceClass(Class listenerServiceClass) {
return (AndroidRefWatcherBuilder)this.heapDumpListener(new ServiceHeapDumpListener(this.context, listenerServiceClass));
}
通过该两种方法发现,AndroidRefWatcherBuilder默认已实现了heapDumpListener和excludedRefs。
最后再来看看AndroidRefWatcherBuilder的buildAndInstall方法,也就是入口install方法最终执行的方法:
public RefWatcher buildAndInstall() {
RefWatcher refWatcher = this.build();
if(refWatcher != RefWatcher.DISABLED) {
LeakCanary.enableDisplayLeakActivity(this.context);
ActivityRefWatcher.installOnIcsPlus((Application)this.context,refWatcher);
}
return refWatcher;
}
该方法主要做了3件事情:build;注册DisplayLeakActivity,用于显示性能统计结果;以及安装LeakCanary。
继续跟进installOnlcsPlus,最终执行了如下方法:
private final ActivityLifecycleCallbacks lifecycleCallbacks = new ActivityLifecycleCallbacks() {
......
public void onActivityDestroyed(Activity activity) {
ActivityRefWatcher.this.onActivityDestroyed(activity);
}
};
public void watchActivities() {
this.stopWatchingActivities();
this.application.registerActivityLifecycleCallbacks(this.lifecycleCallbacks);
}
由此可以得出一个结论,LeakCanary性能统计的原理就是通过监听每个Activity的销毁,在销毁过程中统计该页面的性能情况。
我们再来继续跟进ActivityRefWatcher.this.onActivityDestroyed(activity)方法,最终执行了如下代码片段:
Result ensureGone(KeyedWeakReference reference, long watchStartNanoTime) {
......
this.gcTrigger.runGc();
......
File heapDumpFile =this.heapDumper.dumpHeap();
......
this.heapdumpListener.analyze(newHeapDump(heapDumpFile,reference.key,reference.name, this.excludedRefs,watchDurationMs,gcDurationMs,heapDumpDurationMs));
return Result.DONE;
}
该方法主要做了两件事情:
1,生成性能统计文件.hprof,关键代码如下:
Debug.dumpHprofData(heapDumpFile.getAbsolutePath());
2,分析文件。分析文件的过程在service服务当中,该服务正是入口方法放进去的DisplayLeakService,最终将生成的.hprof文件通过通知的形式呈现出来:
protected final void onHeapAnalyzed(HeapDump heapDump, AnalysisResult result) {
......
LeakCanaryInternals.showNotification(this, contentTitle, contentText, pendingIntent, notificationId1);
}
其中AnalysisResult是.hprof的分析结果。
讲到这里,可能某些读者仍有些疑问,到底.hprof文件是如何解析成信息的?源码的处理的关键语句是这样的:
AnalysisResult result = heapAnalyzer.checkForLeak(heapDump.heapDumpFile, heapDump.referenceKey);
没错,性能统计文件转化为信息的代码正是checkForLeak,具体实现逻辑在HeapAnalyzer里面:
public AnalysisResult checkForLeak(File heapDumpFile, String referenceKey) {
......
MemoryMappedFileBuffer e = new MemoryMappedFileBuffer(heapDumpFile);
HprofParser parser = new HprofParser(e);
Snapshot snapshot = parser.parse();
this.deduplicateGcRoots(snapshot);
Instance leakingRef = this.findLeakingReference(referenceKey, snapshot);
return leakingRef == null ? AnalysisResult.noLeak(this.since(analysisStartNanoTime)) : this.findLeakTrace(analysisStartNanoTime, snapshot, leakingRef);
}
这里,执行转化的方法为HprofParser的parse方法,然后再将转化的信息封装成AnalysisResult对象,其中HprofParser也是自定义的类,里面有一定的篇幅解析.hprof文件,感兴趣的同学可以继续深入研究。
至此,整个LeakCanary的建造以及执行流程已梳理完毕。
网友评论