Android Matrix matrix-resource-canary-android源码分析

前言

上周有一个任务就是要我分析内存中重复的Bitmap的问题的,就是这个Android CMake错误解决的续集。

忙于其他的问题和五一放假,现在才有时间重新看看这个问题是否可以用Matrix解决!╮(╯▽╰)╭

这个问题貌似有点难搞(在不考虑Hook Bitmap接口),不过幸好微信的老哥开源了一个微信的APM工具,里面包含了当Activity销毁的时候发生内存泄漏dump内存中的数据matrix-resource-canary。这个模块是Resource Canary下的,这一部分的功能仅仅是通过系统的Debug类提供的接口将内存中的数据dump到Hprof文件中,然后再通过matrix-resource-canary读取该Hprof文件,分析其中的一些StringId、BitmapId,找到Bitmap的Buffer,找出不需要的数据部分并裁剪,保留String和Bitmap等的对象数据。

这个matrix-resource-canary的模块的触发时机比较傲娇——bitmap问题的分析目前必须依赖activity泄漏检测得到的产物

如果仅仅需要分析Bitmap的问题,需要我们自己去修改检测的逻辑,这个部分还是比较麻烦的,需要理解matrix-resource-canary的原理才可以做出修改和定制。

分析

不多说,先上我分析的图(不严格按照流程图以及类图来画):

在这里插入图片描述

ResourcePlugin

ResourcePlugin是该模块的入口,负责注册Android生命周期的监听以及配置部分参数和接口回调。

ActivityRefWatcher

ResourcePlugin中负责Android生命周期监听的其实是ActivityRefWatcher

ActivityRefWatcher负责的任务其实蛮多的,其中的几个比较重要的功能类都在ActivityRefWatcher中实例化并完成Android Activity内存泄漏时,弹出Dump内存的Dialog、Dump内存数据、读取内存数据裁剪Hprof文件、生成包含裁剪后的Hprof以及泄漏的Activity的信息(进程号、Activity名、时间等)、通知主线程完成内存信息的备份并关闭Dialog。

RetryableTaskExecutor

RetryableTaskExecutor中包含了两个Handler对象,一个mBackgroundHandlermMainHandler,分别给主线程和后台的线程提交任务。默认重试次数是3。

DumpStorageManager

DumpStorageManager这个类功能很简单,其实就是准备Hprof所在的文件夹和创建Hprof文件,方便写入数据到文件中。

AndroidHeapDumper

AndroidHeapDumper这个其实就是封装了android.os.Debug的接口的类。

主要是用系统提供的类android.os.DebugDump内存信息到本地,android.os.Debug会在本地生成一个Hprof文件,也是Matrix需要分析和裁剪的原始文件。

  • 问什么要裁剪?
    • 原始的Hprof文件动不动就几百兆,如果不裁剪、压缩,文件太大了。
    • 流程化,可以通过Matrix提供的工具直接还原内存泄漏的的Bitmap原图,并提供泄漏的引用链。

一般Dump一次要5s~15s之间,所以不能做成线上的。

Dump的时候,AndroidHeapDumper会展示一个Dialog提示当前正在Dump中,Dump完毕就会将Dialog关闭。

AndroidHeapDumper.HeapDumpHandler

这个是裁剪Hprof操作的核心部分了,所有的核心逻辑都在这里面。

让我们先看看AndroidHeapDumper.HeapDumpHandler的实例化过程吧。

public static class ComponentFactory {

        protected RetryableTaskExecutor createDetectExecutor(ResourceConfig config, HandlerThread handlerThread) {
            return new RetryableTaskExecutor(config.getScanIntervalMillis(), handlerThread);
        }

        protected DumpStorageManager createDumpStorageManager(Context context) {
            return new DumpStorageManager(context);
        }

        protected AndroidHeapDumper createHeapDumper(Context context, DumpStorageManager dumpStorageManager) {
            return new AndroidHeapDumper(context, dumpStorageManager);
        }

        // 创建一个按照队列顺序执行任务的Service
        protected AndroidHeapDumper.HeapDumpHandler createHeapDumpHandler(final Context context, ResourceConfig resourceConfig) {
            return new AndroidHeapDumper.HeapDumpHandler() {
                @Override
                public void process(HeapDump result) {
                    CanaryWorkerService.shrinkHprofAndReport(context, result);
                }
            };
        }
    }

AndroidHeapDumper.HeapDumpHandler负责将本地的Hprof文件的信息类HeapDump交由CanaryWorkerService去执行裁剪的操作。

CanaryWorkerService

继承自MatrixJobIntentService,MatrixJobIntentService继承自Service。

找出Activity泄漏的引用链、Bitmap、裁剪Hprof文件,之后将引用链、进程号、时间、Activity名称等写入文件result.info中,并和裁剪后的Hprof文件一起压缩到zip格式的压缩包中。

CanaryWorkerService.doShrinkHprofAndReport中可以找到new HprofBufferShrinker().shrink(hprofFile, shrinkedHProfFile);,这是一个封装了裁剪逻辑的组合类。

让我们看看实现:

public void shrink(File hprofIn, File hprofOut) throws IOException {
    ...

    // 使用了访问者模式
    final HprofReader reader = new HprofReader(new BufferedInputStream(is));
    reader.accept(new HprofInfoCollectVisitor());
    // Reset.
    is.getChannel().position(0);
    reader.accept(new HprofKeptBufferCollectVisitor());
    // Reset.
    is.getChannel().position(0);
    reader.accept(new HprofBufferShrinkVisitor(new HprofWriter(os)));

    ...
}
访问者 说明
HprofInfoCollectVisitor 收集一些必备的StringId、ClassId、BufferId以及String实例和Bmp实例。
HprofKeptBufferCollectVisitor 收集需要保留的16进制的地址。
HprofBufferShrinkVisitor 去掉不需要保留的二进制数据【裁剪】。

HprofInfoCollectVisitorHprofKeptBufferCollectVisitorHprofBufferShrinkVisitor均继承自HprofVisitor,由HprofReader代理访问不同Visitor能力。

CanaryResultService

继承自MatrixJobIntentService,MatrixJobIntentService继承自Service。

负责通知主线程Dump、裁剪、压缩数据完毕。

更多

其实还有很多的东西可以写的,比如如何分析Hprof文件,这个有时间再仔细研究下看看。

这里其实就分析了matrix-resource-canary-android的部分,还有解析裁剪后的Hprof文件的命令行库matrix-resource-canary-analyzer没有分析。

CLIMain这个命令行工具需要使用gradlew buildResourceCheckJar编译得到。位于matrix/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-analyzer/build/libs下的matrix-resource-canary-analyzer-0.5.1.jar

  • matrix-resource-canary
    • matrix-resource-canary-android
    • matrix-resource-canary-analyzer
    • matrix-resource-canary-common

这里面很多有意思的知识点可以挖挖看看!O(∩_∩)O

附录

发布了181 篇原创文章 · 获赞 217 · 访问量 45万+

猜你喜欢

转载自blog.csdn.net/Notzuonotdied/article/details/89927610