1. Matrix 基本介绍
Matrix 是微信终端自研的 APM(应用性能管理)系统,通过非侵入式的字节码插桩技术对 Android 应用性能进行全面监控和分析。主要特点:
我们目前主要用Matrix做卡顿,帧率检测,ANR
- 非侵入式监控:通过编译期插桩实现,无需修改业务代码
- 全方位监控:覆盖启动速度、卡顿、内存、ANR等多维度
- 高精度数据:基于 Choreographer 回调机制,监控精度高
- 商业化验证:在微信等大型应用中经过验证
2. 5大核心结构和8大功能
2.1 5大核心组件
1. Trace Canary - 卡顿和ANR监控(重点使用,本文主要讲这个)
Trace Canary 通过 choreographer 回调、编译期插桩的方式,实现了高准确率、高性能的卡顿检测、定位方案,并扩展支持了多个其它流畅性指标,包括:
- 界面流畅性评估
- 卡顿定位
- ANR监控
- 应用启动及界面切换耗时监控
- Resource Canary - 内存泄漏检测
- APK Checker - APK分析检测
- SQLite Lint - 数据库使用优化
- IO Canary - 文件IO监控
Matrix-android 主要包含 多个组件:通过统一对外接口 Matrix 配置完成后执行。每一个模块相当于一个 Plugin,在执行初始化、启动、停止、销毁、报告问题等操作时,都会回调 PluginListener,并更新状态。
2.2 8大功能模块
- 帧率监控 - 实时监控界面流畅度
- 卡顿检测 - 主线程耗时方法监控
- ANR监控 - Application Not Responding检测
-----------------------
- 启动监控 - 应用启动各阶段耗时
- 内存泄漏 - Activity和Bitmap泄漏检测
- 文件IO - 主线程IO和文件泄漏监控
- 数据库优化 - SQLite使用规范检查
- APK分析 - 安装包体积和资源分析
3. Matrix 集成步骤
3.1 基础集成配置
项目根目录 build.gradle:
gradle
buildscript {
ext {
MATRIX_VERSION = "2.1.0"
}
dependencies {
classpath "com.tencent.matrix:matrix-gradle-plugin:${MATRIX_VERSION}"
}
}
模块 build.gradle:
gradle
apply plugin: 'com.tencent.matrix-plugin'
android {
// 排除冲突的so库
packagingOptions {
exclude 'lib/armeabi-v7a/libwechatbacktrace.so'
exclude 'lib/arm64-v8a/libwechatbacktrace.so'
}
}
matrix {
trace {
enable = true
baseMethodMapFile = "${project.buildDir}/matrix_output/Debug.methodmap"
blackListFile = "${project.projectDir}/matrixTrace/blackMethodList.txt"
}
}
dependencies {
implementation "com.tencent.matrix:matrix-android-lib:${MATRIX_VERSION}"
implementation "com.tencent.matrix:matrix-trace-canary:${MATRIX_VERSION}"
implementation "com.tencent.matrix:matrix-io-canary:${MATRIX_VERSION}"
}
初始化Matrix
less
public class MyApp extends Application {
@Override
public void onCreate() {
super.onCreate();
// 初始化Matrix
Matrix.Builder builder = new Matrix.Builder(this);
// 配置卡顿监控模块
builder.plugin(new TraceCanaryPlugin(new TraceConfig() {
@Override
public boolean isFPSEnable() {
return true; // 开启帧率监控
}
@Override
public boolean isEvilMethodTraceEnable() {
return true; // 监控耗时方法
}
@Override
public int getEvilThresholdMs() {
return 500; // 卡顿阈值(毫秒)
}
@Override
public boolean isDebug() {
return BuildConfig.DEBUG; // 调试模式
}
}));
// 可选:添加其他监控模块(如内存泄漏检测)
// builder.plugin(new ResourcePlugin(new ResourceConfig()));
// 初始化Matrix
Matrix.init(builder.build());
// 启动卡顿监控
TraceCanaryPlugin plugin = Matrix.with().getPluginByClass(TraceCanaryPlugin.class);
if (plugin != null) {
plugin.start();
}
}
}
实现动态配置接口,
可修改 Matrix 内部参数. 在 sample-android 中 我们有个简单的动态接口实例DynamicConfigImplDemo.java, 其中参数对应的 key 位于文件 MatrixEnum中, 摘抄部分示例如下:
typescript
public class DynamicConfigImplDemo implements IDynamicConfig {
private static final String TAG = "Matrix.DynamicConfigImplDemo";
public DynamicConfigImplDemo() {
}
public boolean isFPSEnable() {
return true;
}
public boolean isTraceEnable() {
return true;
}
public boolean isSignalAnrTraceEnable() {
return true;
}
public boolean isMatrixEnable() {
return true;
}
@Override
public String get(String key, String defStr) {
//TODO here return default value which is inside sdk, you can change it as you wish. matrix-sdk-key in class MatrixEnum.
// for Activity leak detect
if ((ExptEnum.clicfg_matrix_resource_detect_interval_millis.name().equals(key) || ExptEnum.clicfg_matrix_resource_detect_interval_millis_bg.name().equals(key))) {
Log.d("DynamicConfig", "Matrix.ActivityRefWatcher: clicfg_matrix_resource_detect_interval_millis 10s");
return String.valueOf(TimeUnit.SECONDS.toMillis(5));
}
if (ExptEnum.clicfg_matrix_resource_max_detect_times.name().equals(key)) {
Log.d("DynamicConfig", "Matrix.ActivityRefWatcher: clicfg_matrix_resource_max_detect_times 5");
return String.valueOf(3);
}
return defStr;
}
@Override
public int get(String key, int defInt) {
//TODO here return default value which is inside sdk, you can change it as you wish. matrix-sdk-key in class MatrixEnum.
if (MatrixEnum.clicfg_matrix_resource_max_detect_times.name().equals(key)) {
MatrixLog.i(TAG, "key:" + key + ", before change:" + defInt + ", after change, value:" + 2);
return 2;//new value
}
if (MatrixEnum.clicfg_matrix_trace_fps_report_threshold.name().equals(key)) {
return 10000;
}
if (MatrixEnum.clicfg_matrix_trace_fps_time_slice.name().equals(key)) {
return 12000;
}
return defInt;
}
@Override
public long get(String key, long defLong) {
//TODO here return default value which is inside sdk, you can change it as you wish. matrix-sdk-key in class MatrixEnum.
if (MatrixEnum.clicfg_matrix_trace_fps_report_threshold.name().equals(key)) {
return 10000L;
}
if (MatrixEnum.clicfg_matrix_resource_detect_interval_millis.name().equals(key)) {
MatrixLog.i(TAG, key + ", before change:" + defLong + ", after change, value:" + 2000);
return 2000;
}
return defLong;
}
@Override
public boolean get(String key, boolean defBool) {
//TODO here return default value which is inside sdk, you can change it as you wish. matrix-sdk-key in class MatrixEnum.
return defBool;
}
@Override
public float get(String key, float defFloat) {
//TODO here return default value which is inside sdk, you can change it as you wish. matrix-sdk-key in class MatrixEnum.
return defFloat;
}
}
处理卡顿监听
实现 PluginListener,接收 Matrix 处理后的数据, 如:
java
public class MatrixIssueListener implements IssueListener {
@Override
public void onIssue(Issue issue) {
if (issue instanceof AnrIssue) {
// 处理ANR事件
AnrIssue anrIssue = (AnrIssue) issue;
Log.e("Matrix", "ANR发生: " + anrIssue.getProcessName());
} else if (issue instanceof EvilMethodIssue) {
// 处理卡顿事件
EvilMethodIssue evilMethodIssue = (EvilMethodIssue) issue;
Log.e("Matrix", "卡顿发生: " + evilMethodIssue.getStack());
}
// 上传数据到服务器或保存本地
reportToServer(issue);
}
}
// 在初始化Matrix后设置监听器
TraceCanaryPlugin plugin = Matrix.with().getPluginByClass(TraceCanaryPlugin.class);
if (plugin != null) {
plugin.setIssueListener(new MatrixIssueListener());
}
测试是否集成成功
typescript
package com.example.matrixdemo;
import android.os.Bundle;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import com.blankj.utilcode.util.LogUtils;
public class MainActivity extends AppCompatActivity {
public TextView textView;
private static final String TAG = "MatrixLog";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
textView = findViewById(R.id.tv_test);
textView.setOnClickListener(v -> testThreadAnr());
}
private void testThreadAnr() {
try {
int number = 0;
while (number++ < 5) {
LogUtils.e(TAG, "主线程睡眠导致的ANR:次数" + number + "/5");
try {
Thread.sleep(5000L);
} catch (InterruptedException e) {
e.printStackTrace();
LogUtils.e(TAG, "异常信息为:" + e.getMessage());
}
}
} catch (Throwable e) {
e.printStackTrace();
LogUtils.e(TAG, "异常信息为:" + e.getMessage());
}
}
}
过滤TAG: Matrix,如果有下面的日志打印,说明集成成功了

3.2 Matrix 编译问题解决方案
常见问题1:zipalign工具不存在
gradle
matrix {
// Windows平台
apksignerPath = "${android.sdkDirectory}/build-tools/${android.buildToolsVersion}/apksigner.bat"
zipAlignPath = "${android.sdkDirectory}/build-tools/${android.buildToolsVersion}/zipalign.exe"
// Mac平台
// apksignerPath = "${android.sdkDirectory}/build-tools/${android.buildToolsVersion}/apksigner"
// zipAlignPath = "${android.sdkDirectory}/build-tools/${android.buildToolsVersion}/zipalign"
}
常见问题2:Kotlin版本冲突
gradle
// 在项目根目录build.gradle中添加
allprojects {
configurations.all {
resolutionStrategy {
force "org.jetbrains.kotlin:kotlin-stdlib:1.6.21"
force "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.6.21"
force "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.6.21"
}
}
}
3.3 Matrix只在debug环境才打包,release不生效的办法,gradle的配置
BuildConfig配置:
gradle
android {
buildTypes {
debug {
buildConfigField "boolean", "ENABLE_MATRIX", "true"
}
release {
buildConfigField "boolean", "ENABLE_MATRIX", "false"
}
}
}
依赖隔离配置:
gradle
dependencies {
debugImplementation "com.tencent.matrix:matrix-android-lib:${MATRIX_VERSION}"
debugImplementation "com.tencent.matrix:matrix-trace-canary:${MATRIX_VERSION}"
// Release版本不打包Matrix
releaseImplementation "com.tencent.matrix:matrix-android-lib:${MATRIX_VERSION}" {
exclude group: 'com.tencent.matrix', module: 'matrix-trace-canary'
}
}
4. 集成微信官方Demo指南
微信 Matrix 官方文档:

4.1 解决编译和运行问题
Demo运行步骤:
- 克隆官方仓库:
git clone https://github.com/Tencent/matrix.git
- 导入
sample-android
模块 - 修改gradle.properties中的版本配置
- 同步项目并运行
4.2 Matrix报告数据字段解读
官网的说明: github.com/Tencent/mat...
后面根据详细案例分析
通用字段:
json
{
"type": "问题类型",用于区分同一个tag不同类型的上报
"tag": "问题标签(Trace_EvilMethod/Trace_FPS等)",
"process": "进程名",
"time": "时间戳",
stack:该上报对应的堆栈 // 重点
}
卡顿相关字段:
json
{
"cost": 804, // 耗时(ms)
"usage": "0.37%", // CPU使用率
"scene": "发生场景",
"stack": "堆栈信息"
}
trace(包括启动、慢函数和 FPS 三种)
共同字段:
- machine: 区分设备好坏的字段
- process: 进程
启动
- tag: Trace_StartUp
- scene: 对应的场景
- application_create:应用启动的耗时
- first_activity_create:activity 启动耗时
- stage_between_app_and_activity: 介于应用和 activity 两者之间的耗时
- splash_activity_duration,欢迎页耗时
- startup_duration 启动总耗时
- is_warm_start_up: 是否是软启动,值范围: true 和 false
- application_create_scene:启动的场景
- 100 (activity拉起的)
- 114(service拉起的)
- 113 (receiver拉起的)
- -100 (未知,比如contentprovider)
json
{"machine":4,"application_create":415,"first_activity_create":240,"stage_between_app_and_activity":0,"scene":"com.tencent.mm.app.WeChatSplashActivity","is_warm_start_up":false,"tag":"Trace_StartUp","process":"com.tencent.mm","time":1528278018147}
5. 官网Demo案例与分析
卡顿包含5大项,anr,fps,卡顿,慢方法,启动检测

5.1 ANR案例检测与报告解读
ANR(有anr和慢方法监控上报)
测试代码:
java
public void testSignalANR(final View view) {
try {
// 主线程睡眠20秒触发ANR
Thread.sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
日志打印:

生成的json报告

ANR报告分析:
json
{
"detail": "ANR",
"cost": 5000, // ANR耗时
"threadStack": "堆栈详情",
"stackKey": "", // ANR调用栈
}
关键4指标:
- "detail": "ANR", // 类型
cost > 5000ms
:ANR阈值- "stackKey": "", // ANR调用栈
threadStack
:阻塞调用栈
双重标记:同时被标记为ANR和慢方法,说明Matrix检测到了主线程5秒无响应!
会导致2个,ANR和慢方法同时都有
AnrTracer
ANR完整的json报告:
swift
{
"machine": "MIDDLE", // 设备性能等级:MIDDLE(中等性能设备)
"cpu_app": 0, // 应用CPU使用率:0%(发生ANR时CPU可能被完全阻塞)
"mem": 5983535104, // 设备总内存:5,983,535,104 bytes(约5.57GB)
"mem_free": 1905028, // 设备可用内存:1,905,028 bytes(约1.82MB)
"detail": "ANR", // 问题类型:ANR(Application Not Responding)
"cost": 5000, // ANR耗时:5000ms(5秒,达到ANR阈值)
"stackKey": "1024", // 堆栈标识key:1024(用于唯一标识此问题)
"scene": "sample.tencent.matrix.trace.TestTraceMainActivity", // 发生场景:TestTraceMainActivity页面
"stack": "1024,10399303,3322", // 简化堆栈信息(需要结合methodMapping文件解析)
"threadStack": " \n|*\t\tat android.os.SystemClock:sleep(131)\n|*\t\tat sample.tencent.matrix.trace.TestTraceMainActivity:L(204)\n|*\t\tat sample.tencent.matrix.trace.TestTraceMainActivity:A(150)\n|*\t\tat sample.tencent.matrix.trace.TestTraceMainActivity:testANR(132)\n|*\t\tat java.lang.reflect.Method:invoke(-2)\n|*\t\tat android.view.View$DeclaredOnClickListener:onClick(6585)\n|*\t\tat android.view.View:performClick(7771)\n|*\t\tat android.view.View:performClickInternal(7748)\n|*\t\tat android.view.View:access$3700(854)\n", // 详细线程堆栈
"processPriority": 10, // 进程优先级:10(较高优先级)
"processNice": -10, // 进程nice值:-10(高优先级,更易获取CPU时间)
"isProcessForeground": true, // 是否前台进程:是(用户正在交互的进程)
"memory": { // 内存使用详情
"dalvik_heap": 4722, // Dalvik堆内存使用:4,722KB
"native_heap": 24666, // Native堆内存使用:24,666KB
"vm_size": 6679844 // 虚拟内存大小:6,679,844KB
},
"tag": "Trace_EvilMethod", // 问题标签:同时被标记为慢方法(ANR本质上是极端的慢方法)
"process": "sample.tencent.matrix", // 进程名称:sample.tencent.matrix
"time": 1728803978731 // 时间戳:2023年10月13日左右(Unix毫秒时间戳)
}
5.2 卡顿: 慢方法案例检测与报告解读
测试代码:
java
private void simulateBlock() {
SystemClock.sleep(800); // 模拟800ms卡顿
heavyCalculation(); // 耗时计算
}
卡顿的日志打印:

卡顿报告分析: demo的报告
json
{
"tag": "Trace_EvilMethod",
"type": 0,
"process": "sample.tencent.matrix",
"time": 1590407411286,
"machine": "HIGH",
"cpu_app": 8.439117339531338E-4,
"mem": 3030949888,
"mem_free": 1656536,
"detail": "NORMAL",
"cost": 804, // 方法执行总耗时
"usage": "0.37%", // 在方法执行总时长中,当前线程占用的 CPU 时间比例
"scene": "sample.tencent.matrix.trace.TestTraceMainActivity",
"stack": "0,1048574,1,804\n1,14,1,803\n2,29,1,798\n",
"stackKey": "29|"
}
5.2.3 定位是哪个方法,stack数据解读分析
特殊字段如下:
- tag: Trace_EvilMethod
- detail,具体的耗时场景
a. NORMAL, 普通慢函数场景
b. ENTER, Activity进入场景
c. ANR, anr超时场景
d. FULL, 满buffer场景 e. STARTUP, 启动耗时场景
- cost: 耗时
- stack: 堆栈
- stackKey: 客户端提取的 key,用来标识 issue 的唯一性
如果 detail == ENTER, 会增加viewInfo字段, 包括一下三个属性:
- viewDeep: view 的深度,是个整数
- viewCount: view 的数量,是个整数
- activity: activity 的 name
如果 detail == STARTUP, 会增加subType 字段,默认值-1
- subType=1,代表application初始化过程的堆栈
- subType=2,代表启动第一个界面初始化过程的堆栈
5.2.4 看慢方法的具体指标和步骤
1). "tag": "Trace_EvilMethod",
2). scene:出问题的地方
3). "cost": 804, // 方法执行总耗时
4). "stack": "0,1048574,1,804\n1,14,1,803\n2,29,1,798\n",
生成的目录:
Matrix在编译时会生成一个methodMapping.txt文件,这个文件记录了我们项目里所有方法的对应的id,我们拿到上面的stack数据后,根据里面的数据来对照这张methodMapping表格,就能知道具体是哪个方法了。
堆栈解析:
使用methodMapping.txt
解析方法ID:
0,1048574,1,804
:层级0,方法ID1048574,调用1次,耗时804ms- 通过mapping文件查找具体方法名
一般自己写个脚本,自动分析出,是那个方法ID导致的卡顿
这里我把数据换行了下,方便大家阅读,可以看到这里每一行都有4个数据如"3,195,1,10"、"1,33,1,58"、"2,206,1,21"。
- 第一个数字代表:该方法在堆栈里的层级。
- 第二个数字代表:该方法在methodMapping表格的id。
- 第三个数字代表:该方法被调用的次数。
- 第四个数字代表:该方法具体的耗时。


json
{
"tag": "Trace_EvilMethod", // 问题标签:标识为慢方法检测
"type": 0, // 问题类型:0表示普通类型问题
"process": "sample.tencent.matrix", // 进程名称:sample.tencent.matrix
"time": 1590407411286, // 时间戳:2020年5月25日左右(Unix毫秒时间戳)
"machine": "HIGH", // 设备性能等级:HIGH(高性能设备)
"cpu_app": 8.439117339531338E-4, // 应用CPU使用率:0.0008439(约0.084%)
"mem": 3030949888, // 设备总内存:3,030,949,888 bytes(约2.82GB)
"mem_free": 1656536, // 设备可用内存:1,656,536 bytes(约1.58MB)
"detail": "NORMAL", // 问题详情类型:NORMAL(普通慢方法,非ANR等特殊类型)
"cost": 804, // 方法执行总耗时:804毫秒(超过默认500ms阈值)
"usage": "0.37%", // CPU使用比例:在执行总时长中,线程实际占用CPU时间的比例
"scene": "sample.tencent.matrix.trace.TestTraceMainActivity", // 发生场景:TestTraceMainActivity页面
"stack": "0,1048574,1,804\n1,14,1,803\n2,29,1,798\n", // 方法调用堆栈(需要methodMapping文件解析)
"stackKey": "29|" // 堆栈关键标识:标识问题唯一性的key,基于方法ID29生成
}
堆栈数据解析说明:
堆栈格式:层级,方法ID,调用次数,耗时(ms)
0,1048574,1,804
:最外层方法,ID为1048574,调用1次,总耗时804ms1,14,1,803
:第二层方法,ID为14,调用1次,耗时803ms2,29,1,798
:最内层方法,ID为29,调用1次,耗时798ms(性能问题)
动画卡顿:
问题:帧动画卡顿,或者view卡顿,怎么分析出来的?
帧率是一方面,帧率并不是很准, 用慢方法是分析不出来的!

Matrix慢方法分析在动画卡顿检测中的定位:
- ✅ 擅长:主线程阻塞、复杂计算、IO操作导致的卡顿
- ❌ 局限:GPU渲染、VSync丢失、纯渲染性能问题
- 🔄 最佳实践 :结合慢方法 + FPS + 帧耗时分析 进行综合诊断
5.3 FPS帧率检测案例

FPS的指标:
帧率:fps的使用:
帧率这边需要统计整体帧率,已经按场景统计帧率情况
- tag: Trace_FPS
- scene:帧率对应的场景
- dropLevel:衡量帧率掉帧的水平
- dropSum:总共掉帧的总时长
- fps: 帧率
会有不同的等级帧率监控!
- frozen级别-丢帧大于42
- high级别-丢帧介于24到42
- middle级别-丢帧介于9到24
- mormal级别-丢帧介于3到9
- best级别-丢帧小于3
官方的demo场景:RecyclerView卡顿导致的掉帧

- 列表快速滚动
- 复杂动画渲染
- 大量视图更新
日志:


注意: 发现一个问题: 每隔10s就会上报一次,(看源码可以知道)
并且如果没有卡顿,帧率显示也是20多,不正常
正常情况:

异常情况:

FPS报告分析:
json
{
"tag": "Trace_FPS",
"fps": 46.39,
"dropLevel": {
"DROPPED_FROZEN": 0,
"DROPPED_HIGH": 0,
"DROPPED_MIDDLE": 3,
"DROPPED_NORMAL": 14,
"DROPPED_BEST": 451
}
}
性能等级标准:
- 优秀:fps ≥ 55
- 良好:45 ≤ fps < 55
- 一般:30 ≤ fps < 45
- 卡顿:fps < 30
5.4 慢方法插桩案例
插桩配置:
gradle
matrix {
trace {
enable = true
blackListFile = "${project.projectDir}/blackMethodList.txt"
}
}
黑名单配置示例:
bash
# 排除系统方法
android.#*#
com.android.#*#
# 排除第三方库
com.tencent.matrix.#*#
# 排除特定方法
com.example.MainActivity#onCreate
监控原理: Matrix在编译期插入监控代码:
java
// 原始代码
public void businessMethod() {
// 业务逻辑
}
// 插桩后代码
public void businessMethod() {
AppMethodBeat.i(METHOD_ID); // 方法开始
// 业务逻辑
AppMethodBeat.o(METHOD_ID); // 方法结束
}
5.5 启动速度监控
这里不做详细说明,和之前的差不多

6. Matrix 高级配置与优化
6.1 动态参数配置
java
public class DynamicConfigImpl implements IDynamicConfig {
@Override
public int getEvilThresholdMs() {
// 根据不同设备动态调整卡顿阈值
if (isLowEndDevice()) {
return 1000; // 低端设备放宽阈值
}
return 500; // 高端设备严格阈值
}
}
6.2 自定义监控策略
java
public class CustomTraceConfig extends TraceConfig {
@Override
public boolean isFPSEnable() {
return true; // 开启FPS监控
}
@Override
public int getFrameDurationBugly() {
return 700; // 调整帧耗时阈值
}
}
6.3 数据上报优化
java
public class MatrixIssueListener implements IssueListener {
@Override
public void onIssue(Issue issue) {
// 采样上报,避免数据量过大
if (shouldReport(issue)) {
uploadToServer(issue);
}
// 本地记录重要问题
if (isCriticalIssue(issue)) {
saveToLocal(issue);
}
}
}
通过以上完整的集成指南和案例分析,您应该能够成功集成Matrix并有效监控应用性能问题。Matrix提供了丰富的配置选项和监控维度,可以根据具体业务需求进行定制化配置。
7. Matrix监控工具5者的的对比优缺点
Looper,BlockCanary,都是有非常的缺陷和误差,只有Matrix是百分百对的,主要重点分析其他监控框架的缺点和原理
五种卡顿监控工具对比总表
监控方案 | 原理 | 优点 | 缺点 | 适用场景 |
---|---|---|---|---|
ANRWatchDog | 子线程轮询:子线程循环向主线程发送消息,检测消息是否在阈值内被处理。 | 1. 实现简单 2. 稳定可靠 ,结果论 3. 可监控各种类型的卡顿(包括Native阻塞) | 1. 轮询不优雅 ,耗性能 2. 随机漏报 (误差在轮询间隔内) 3. 无法定位耗时方法 ,只知道发生了卡顿 4. 不准确:5s阈值与ANR定义不符 | 线下快速验证、对精度要求不高的简单监控 |
BlockCanary | Looper Printer :替换Looper 的mLogging 对象,计算dispatchMessage 的执行耗时。 |
1. 准确率高 ,无随机漏报 2. 可获取卡顿堆栈 3. 集成简单,功能强大(UI展示、堆栈信息全) | 1. 字符串拼接 导致内存抖动 (线上禁用) 2. 高频采样堆栈 对性能有影响 3. 无法监控 queue.next() 等处的卡顿 |
线下开发、测试阶段的首选工具,用于精准定位问题 |
Looper Printer (Matrix方案) | 优化版Printer:Matrix对上述方案的优化实现。 | 1. 解决了字符串拼接 问题,可用于线上 2. 继承了Printer方案的准确性 3. 与Matrix其他插件(帧率、资源等)联动 | 1. 依然无法监控 IdleHandler 、SyncBarrier 泄漏等盲区 2. 需要集成整个Matrix库 |
线上环境监控主线程耗时和卡顿 |
Choreographer FrameCallback | 帧生命周期回调 :通过postFrameCallback 在每一帧绘制前后回调,计算帧耗时。 |
1. 官方API ,兼容性好 2. 功能强大 :既可监控卡顿 ,也可计算帧率FPS 3. 性能损耗相对较低 | 1. 只能监控doFrame耗时 ,无法感知消息队列拥堵 2. 获取的堆栈无法关联到具体业务方法 3. 需要另开线程采样堆栈 | 线上监控FPS 和渲染耗时,适合做性能大盘数据采集 |
Matrix (TraceCanary) | 字节码插桩 + Looper监控:在编译期通过ASM在关键方法前后插桩,结合Looper监控。 | 1. 最精准 :可定位到具体耗时方法 2. 覆盖全面 :无监控盲区(包括IdleHandler ) 3. 线上友好 :性能开销可控,细节丰富 4. 功能完善:集成卡顿、帧率、内存等多维度监控 |
1. 集成复杂 ,需要理解Transform/ASM 2. 有代码侵入性 (插桩) 3. 包体积增大 4. 需要后端配合处理海量数据 | 对监控精度要求极高的线上环境,如大型App的核心性能监控体系 |
监控准确性 & 覆盖度 (从高到低)
Matrix (插桩) > Looper Printer ≈ BlockCanary > FrameCallback > ANRWatchDog
markdown
- `Matrix`通过插桩能拿到最精确的方法耗时,覆盖所有场景。
- `Looper Printer`能准确监控`dispatchMessage`耗时,但存在盲区。
- `FrameCallback`只能监控`doFrame`执行期,如果是因为消息排队导致的延迟,它无法感知。
- `ANRWatchDog`最不准确,误差最大。

项目源码的地址:github.com/pengcaihua1...