美文网首页
LeakCanary源码解读

LeakCanary源码解读

作者: android_hcf | 来源:发表于2017-06-14 15:22 被阅读86次

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

    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的建造以及执行流程已梳理完毕。

    相关文章

      网友评论

          本文标题:LeakCanary源码解读

          本文链接:https://www.haomeiwen.com/subject/kiusqxtx.html