前言:
之前根据 Android Studio Profiler 查看卡顿问题 已经解决了部分已知问题「即:有明确场景,进而暴露出来的问题」;
不足的点是:问题暴露之前寻找卡顿的点,抓取的 hprof 文件操作复杂,寻找问题时效率较低,具体每个函数的耗时不可统计 ;
所以需要寻找比较成熟的卡顿工具,帮助我们定位问题.
工具对比:
BlockCanary: 依赖主线程 Looper,监控每次 dispatchMessage 的执行耗时;
ArgusAPM / LogMonitor: 依赖 Choreographer 模块,监控相邻两次 Vsync 事件通知的时间差;
以上方式的问题:
无法获取到各个函数的执行耗时,对于稍微复杂一点的堆栈,很难找出可能耗时的函数,也就很难找到卡顿的原因;
通过其他线程循环获取主线程的堆栈,如果稍微处理不及时,很容易导致获取的堆栈有所偏移,不够准确,加上没有耗时信息,卡顿也就不好定位;
Matrix-TraceCanary 优势:
在编译期间修改字节码;
准确定位卡顿函数,并显示堆栈/执行次数/耗时;
使用问题:
TraceCanary 暴露 3 种类型问题:
Trace_StartUp「启动」
Trace_EvilMethod「慢函数」
Trace_FPS「帧率」
其中 Trace_EvilMethod 模块中所给数据格式如下:
{
"machine":"MIDDLE",
"cpu_app":0.05800059283652189,
"mem":6124523520,
"mem_free":3195336,
"detail":"NORMAL",
"cost":230,
"usage":"87.34%",
"scene":"com.*.android.pokekara.*.main.*Activity",
"stack":"0,1048574,1,230\n1,30791,1,226\n2,30756,1,226\n3,30754,1,226\n4,22474,1,226\n5,22603,1,226\n6,145827,1,204\n7,145985,1,199\n8,139523,1,128\n9,180666,1,128\n10,180669,1,128\n11,29838,1,11\n12,29855,1,11\n8,139524,1,66\n9,21060,1,66\n10,21116,1,49\n11,21207,1,17\n12,28079,1,17\n13,28035,1,17\n14,29464,1,17\n15,28388,1,17\n16,28293,1,17\n17,28296,1,17\n18,60995,1,12\n11,21145,1,11\n12,21152,1,11\n10,21063,1,12\n11,142855,1,12\n12,142531,1,12\n13,142851,1,12\n",
"stackKey":"145985|",
"tag":"Trace_EvilMethod",
"process":"com.*.android.*",
"time":1650008010859,
"type":0,
"build_id":"1650007387169",
"device_id":"6862573909639700608",
"upload_time":1650008010860
}
stack 为调用堆栈;
stackKey 则能唯一标识调用堆栈;
本文只针对 stack 如何解析,以方便开发人员定位问题;
matrix-stack 详解:
stack每行格式:stack层级,方法id,方法执行次数,方法执行总耗时;
methodmap是插桩函数表,每行格式:方法id,方法accessType,类名,方法名,方法描述;
使用:
- 将 matrix 生成的 methodMapping.txt 保存下来「每一次 build,会生成唯一对应 methodMapping.txt」;
- 根据 stack 生成 stack.log 文件,这块是我自己用 python 写的,最后生成 stack.log 文件如下:
0,1048574,1,300\n
1,29689,1,283\n
2,4534,1,283\n
...
11,83065,1,278\n
15,78775,1,278\n
...
24,3174,1,123\n
20,81443,1,67\n
注:上面的文件不能含有多余空格 按照格式去写;
- matrix-trace-processor download 项目到本地,执行python脚本,生成
python3 main.py workflow_traces stack.log > stack_processor.txt methodMapping.txt
此时 stack_processor.txt 已经是 DTrace 格式的堆栈文件,可以利用 FlameGraph 这个库生成火焰图,方便开发者生成调用栈;
注:这个库同样有脚本可以根据 stack 生成 log 文件,但是我认为使用不方便,可以看这里matrix-trace-processor 解析
- FlameGraph项目到本地,执行脚本
stackcollapse.pl stack_processor.txt > stack.folded
flamegraph.pl stack.folded > stack.svg
最终将 stack 的 string 转化为可直接在浏览器打开的 svg 格式的调用栈
注:电脑若为 windows 需要查看 perl 是否安装,上面的脚本文件是用 perl 写的
检查 perl 是否已安装:
perl -v
最终生成的文件如下:
经过上面的步骤,自己开发用来检测已经可以了,but 我「Andorid」做了一个 python 项目「因为后端没人鸟我」,把 matrix 的日志上报到服务端,可根据 方法耗时cost 和 stackKey 去查看 svg 文件,方便组内人员开发;
需要 python + 数据库,就能做这个事情,有兴趣可以整一下;