LeakCanary源码解读

版权声明:本文为原创文章,未经允许不得转载。

LeakCanary是一个安卓的性能统计工具,想必大家都有使用,工具出自大名鼎鼎的Jake Wharton大神,截止目前为止其在GitHub的star数目已达到15.4k,可见其受到的欢迎程度,下面我将通过UML类图以及流程图,最后配上部分源码对源码进行解析。

一、LeakCanary流程图

LeakCanary的代码风格主要使用的是Builder建造者模式,其主要的思想也就是监听Activity的销毁,然后进行性能统计,目前其仅支持SDK14版本及以上,不过已覆盖绝大多数手机。其流程图很简单,如下:

LeakCanary源码解读_第1张图片
LeakCanary流程图.png

如图可见,直到执行buildAndInstall()之前都是搜集所需属性,然后通过buildAndInstall()方法执行安卓统计。这里仅仅是让大家有个整体的执行流程的了解。

二、LeakCanary类图

LeakCanary源码解读_第2张图片
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的建造以及执行流程已梳理完毕。

你可能感兴趣的:(LeakCanary源码解读)