android 获取资源的原理,Android 性能监控框架 Matrix(1)内存泄漏监控及原理介绍...

ResourceCanary 介绍

Matrix 的内存泄漏监控是由 ResourceCanary 实现的,准确的说,ResourceCanary 只能实现 Activity 的内存泄漏检测,但在出现 Activity 内存泄漏时,可以选择 dump 一个堆转储文件,通过该文件,可以分析应用是否存在重复的 Bitmap。

使用

ResourceCanary 是基于 WeakReference 特性和 Square Haha 库开发的 Activity 泄漏和 Bitmap 重复创建检测工具,使用之前,需要进行如下配置:

Matrix.Builder builder = new Matrix.Builder(this);

// 用于在用户点击生成的问题通知时,通过这个 Intent 跳转到指定的 Activity

Intent intent = new Intent();

intent.setClassName(this.getPackageName(), "com.tencent.mm.ui.matrix.ManualDumpActivity");

ResourceConfig resourceConfig = new ResourceConfig.Builder()

.dynamicConfig(new DynamicConfigImplDemo()) // 用于动态获取一些自定义的选项,不同 Plugin 有不同的选项

.setAutoDumpHprofMode(ResourceConfig.DumpMode.AUTO_DUMP) // 自动生成 Hprof 文件

// .setDetectDebuger(true) //matrix test code

.setNotificationContentIntent(intent) // 问题通知

.build();

builder.plugin(new ResourcePlugin(resourceConfig));

// 这个类可用于修复一些内存泄漏问题

ResourcePlugin.activityLeakFixer(this);

复制代码

如果想要在具体的 Activity 中检测内存泄漏,那么获取 Plugin 并执行 start 方法(一般在 onCreate 方法中执行)即可:

Plugin plugin = Matrix.with().getPluginByClass(ResourcePlugin.class);

if (!plugin.isPluginStarted()) {

plugin.start();

}

复制代码

捕获到问题后,会上报信息如下:

{

"tag": "memory",

"type": 0,

"process": "sample.tencent.matrix",

"time": 1590396618440,

"activity": "sample.tencent.matrix.resource.TestLeakActivity",

}

复制代码

如果 DumpMode 为 AUTO_DUMP,还会生成一个压缩文件,里面包含一个堆转储文件和一个 result.info 文件,可以根据 result.info 文件发现具体是哪一个 Activity 泄漏了:

{

"tag":"memory",

"process":"com.tencent.mm",

"resultZipPath":"/storage/emulated/0/Android/data/com.tencent.mm/cache/matrix_resource/dump_result_17400_20170713183615.zip",

"activity":"com.tencent.mm.plugin.setting.ui.setting.SettingsUI",

}

复制代码

配置

ResourcePlugin 执行之前,需要通过 ResourceConfig 配置,配置选项有:

public static final class Builder {

private DumpMode mDefaultDumpHprofMode = DEFAULT_DUMP_HPROF_MODE;

private IDynamicConfig dynamicConfig;

private Intent mContentIntent;

private boolean mDetectDebugger = false;

}

复制代码

其中, ContentIntent 用于发送通知。

DumpMode 用于控制检测到问题后的行为,可选值有:

NO_DUMP,是一个轻量级的模式,会回调 Plugin 的 onDetectIssue 方法,但只报告出现内存泄漏问题的 Activity 的名称

SILENCE_DUMP,和 NO_DUMP 类似,但会回调 IActivityLeakCallback

MANUAL_DUMP,用于生成一个通知,点击后跳转到对应的 Activity,Activity 由 ContentIntent 指定

AUTO_DUMP,用于生成堆转储文件

IDynamicConfig 是一个接口,可用于动态获取一些自定义的选项值:

public interface IDynamicConfig {

String get(String key, String defStr);

int get(String key, int defInt);

long get(String key, long defLong);

boolean get(String key, boolean defBool);

float get(String key, float defFloat);

}

复制代码

和 Resource Canary 相关的选项有:

enum ExptEnum {

//resource

clicfg_matrix_resource_detect_interval_millis, // 后台线程轮询间隔

clicfg_matrix_resource_detect_interval_millis_bg, // 应用不可见时的轮询间隔

clicfg_matrix_resource_max_detect_times, // 重复检测多次后才认为出现了内存泄漏,避免误判

clicfg_matrix_resource_dump_hprof_enable, // 没见代码有用到

}

复制代码

实现该接口对应的方法,即可通过 ResourceConfig 获取上述选项的值:

public final class ResourceConfig {

// 后台线程轮询间隔默认为 1min

private static final long DEFAULT_DETECT_INTERVAL_MILLIS = TimeUnit.MINUTES.toMillis(1);

// 应用不可见时,后台线程轮询间隔默认为 1min

private static final long DEFAULT_DETECT_INTERVAL_MILLIS_BG = TimeUnit.MINUTES.toMillis(20);

// 默认重复检测 10 次后,如果依然能获取到 Activity ,才认为出现了内存泄漏

private static final int DEFAULT_MAX_REDETECT_TIMES = 10;

public long getScanIntervalMillis() { ... }

public long getBgScanIntervalMillis() { ... }

public int getMaxRedetectTimes() { ... }

}

复制代码

可以看到,默认情况下,Resource Canary 在应用可见(onForeground)时每隔 1 分钟检测一次,在应用不可见时每隔 20 分钟检测一次。对于同一个 Activity,在重复检测 10 次后,如果依然能通过弱引用获取,那么就认为出现了内存泄漏。

原理介绍

这部分内容摘抄自官方文档。

监测阶段

在监测阶段,对于 4.0 之前的版本,由于没有 ActivityLifecycleCallbacks,而使用反射有性能问题,使用 BaseActivity 又存在侵入性的问题,因此,ResourceCanary 放弃了对 Android 4.0 之前的版本的支持,直接使用 ActivityLifecycleCallbacks 和弱引用来检测 Activity 的内存泄漏。

分析阶段

在分析阶段,由于对 Activity 的强引用链很可能不止一条,因此问题的关键在于找到最短的引用链。比如有如下引用关系:

cb425a3accdc542564f79e09f279eb5d.png

那么,将 GC Root 和 Object 1 的引用关系解除即可。对于多条 GC Root 引用链的情况,多次检测即可,这样至少保证了每次执行 ResourceCanary 模块的耗时稳定在一个可预计的范围内,不至于在极端情况下耽误其他流程。

LeakCanary 已实现了上述算法,但 Matrix 改进了其中的一些问题:

增加一个一定能被回收的“哨兵”对象,用来确认系统确实进行了GC

直接通过 WeakReference.get() 来判断对象是否已被回收,避免因延迟导致误判

若发现某个 Activity 无法被回收,再重复判断 3 次(0.6.5 版本的代码默认是 10 次),以防在判断时该 Activity 被局部变量持有导致误判

对已判断为泄漏的 Activity,记录其类名,避免重复提示该 Activity 已泄漏

从 Hprof 文件获取所有冗余的 Bitmap 对象

对于这个问题,Android Moniter 已经有完整的实现,原理简单粗暴:把所有未被回收的 Bitmap 的数据 buffer 取出来,然后先对比所有长度为 1 的 buffer,找出相同的,记录所属的 Bitmap 对象;再对比所有长度为 2 的、长度为 3 的 buffer……直到把所有 buffer 都比对完,这样就记录了所有冗余的 Bitmap 对象,接着再套用 LeakCanary 获取引用链的逻辑把这些 Bitmap 对象到 GC Root 的最短强引用链找出来即可。

性能开销

在监测阶段,Resource Canary 的周期性轮询是在后台线程执行的,默认轮询间隔为 1min,以微信通讯录、朋友圈界面的帧率作为参考,接入后应用的平均帧率下降了 10 帧左右,开销并不明显。但 Dump Hprof 的开销较大,整个 App 会卡死约 5~15s。

分析部分放到了服务器环境中执行。实际使用时分析一个 200M 左右的 Hprof 平均需要 15s 左右的时间。此部分主要消耗在引用链分析上,因为需要广度优先遍历完 Hprof 中记录的全部对象。

b739ec46bb5c46d9c0aa4ce35ba1ea56.png

关于找一找教程网

本站文章仅代表作者观点,不代表本站立场,所有文章非营利性免费分享。

本站提供了软件编程、网站开发技术、服务器运维、人工智能等等IT技术文章,希望广大程序员努力学习,让我们用科技改变世界。

[Android 性能监控框架 Matrix(1)内存泄漏监控及原理介绍]http://www.zyiz.net/tech/detail-144964.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值