3、性能分析工具(下):Systrace / Perfetto 的抓取与分析,TraceView 与 Method Tracing 的深度使用
上一章我们聊了基础工具,这一章来点硬核的。Systrace 和 Perfetto,说白了就是 Android 性能分析的「CT 机」。TraceView 则是方法级别的「显微镜」。我当年刚接触这些工具时,觉得它们长得差不多,用起来却天差地别。今天咱们就把它们彻底掰开揉碎。
3.1 Systrace:系统级追踪的「老大哥」
Systrace 是 Google 官方提供的系统级性能分析工具。它能抓取 CPU 调度、UI 渲染、进程线程状态等系统信息。我个人习惯用它来排查「卡顿」和「掉帧」问题。
3.1.1 抓取方式
抓取 Systrace 有两种主流方式:
- 命令行抓取:
python systrace.py -t 10 -o trace.html sched gfx view - Android Studio Profiler:直接点击 CPU 录制按钮,选择「System Trace」
我在项目中遇到过一个问题:用命令行抓取时,忘记加 -a 包名 参数,结果抓到的 trace 里全是系统进程,自己的应用线程根本看不到。嗯,这里要注意,一定要指定你的应用包名。
核心参数说明:
| 参数 | 含义 | 我的建议 |
|---|---|---|
| -t | 抓取时长(秒) | 一般 5-10 秒足够 |
| -o | 输出文件名 | 用 .html 后缀 |
| -a | 指定应用包名 | 必填!否则看不到你的线程 |
| sched/gfx/view | 追踪类别 | 排查卡顿必加 gfx 和 view |
3.1.2 如何分析 Systrace
打开生成的 HTML 文件,你会看到一条条彩色长条。别慌,我教你三步看懂它:
- 看 FPS 曲线:绿色代表流畅,黄色或红色代表掉帧。如果出现红色区域,说明那一帧超过了 16ms。
- 看 SurfaceFlinger:这是 Android 的合成线程。如果它出现长时间等待,说明 GPU 处理不过来。
- 看主线程:找到你的应用主线程(通常是 UI Thread)。如果出现大段的灰色块,说明线程在休眠或等待锁。
小技巧:按 W 键可以放大,按 S 键缩小。选中一段区域后,按 M 键可以标记。我经常用这个功能来对比「卡顿前」和「卡顿后」的线程状态。
3.2 Perfetto:Systrace 的「进化版」
Perfetto 是 Systrace 的下一代产品。它支持更细粒度的追踪,比如内存分配、文件 I/O、甚至 GPU 活动。说白了,Systrace 能做的它都能做,Systrace 不能做的它也能做。
3.2.1 抓取与配置
Perfetto 的抓取方式更灵活:
- 通过 adb 命令:
adb shell perfetto -c /data/local/tmp/config.pbtx -o /data/local/tmp/trace.perfetto-trace - 通过 Perfetto UI:在浏览器中打开
ui.perfetto.dev,点击「Record new trace」
我曾经踩过一个坑:用默认配置抓取 Perfetto,结果 trace 文件太大(几百 MB),分析时浏览器直接卡死。后来我学会了用 buffer_size_kb 和 duration_ms 来控制数据量。
避坑指南:我曾经在生产环境上抓取 Perfetto,忘记关闭「heap_profiler」选项,结果导致应用内存暴涨,直接 OOM 了。切记:线上环境只抓必要的数据,不要开全量追踪。
3.2.2 分析 Perfetto 的核心思路
Perfetto 的 UI 比 Systrace 更强大。我一般按这个顺序分析:
- 看时间轴概览:先看整体趋势,有没有明显的「尖峰」或「断层」。
- 看 CPU 调度:点击 CPU 行,查看每个核心的负载。如果某个核心长时间 100%,说明有计算密集型任务。
- 看线程状态:绿色代表运行中,蓝色代表可运行(等待 CPU),灰色代表休眠。如果蓝色块太多,说明 CPU 不够用。
- 看 Binder 调用:Binder 是 Android 进程间通信的核心。如果 Binder 调用耗时过长,说明跨进程操作有问题。
实战案例:有一次我排查一个列表滑动卡顿问题。用 Perfetto 一看,发现主线程每隔 200ms 就发起一次 Binder 调用,耗时约 50ms。原来是一个后台服务频繁回调 UI 更新。优化方案:合并回调,改为批量更新。卡顿瞬间消失。
3.3 TraceView:方法级别的「手术刀」
TraceView 是 Android Studio 内置的方法追踪工具。它能记录每个方法的调用次数、耗时、调用栈等信息。说白了,就是帮你找到「哪个方法最慢」。
3.3.1 两种追踪模式
| 模式 | 原理 | 开销 | 适用场景 |
|---|---|---|---|
| Sample 采样 | 每隔一段时间采样调用栈 | 低 | 快速定位热点 |
| Instrument 插桩 | 在每个方法入口/出口插入计时代码 | 高 | 精确分析单次调用 |
我个人习惯先用 Sample 模式快速扫描,找到可疑方法后,再用 Instrument 模式做精确分析。你想想看,如果一上来就用 Instrument 模式,抓取 10 秒可能产生几百 MB 数据,分析起来反而更慢。
3.3.2 如何读懂 TraceView 数据
打开 TraceView 文件后,你会看到两个主要视图:
- Call Chart:调用图,展示方法间的调用关系。每个方法用一条横线表示,长度代表耗时。
- Top Down / Bottom Up:自上而下/自下而上的调用树。Top Down 看「谁调用了谁」,Bottom Up 看「谁被谁调用」。
我记得有一次,我用 TraceView 分析一个图片加载库。从 Top Down 视图发现,BitmapFactory.decodeStream 占了 80% 的时间。但奇怪的是,这个方法的子调用里并没有明显的耗时点。后来我用 Bottom Up 视图一看,发现 decodeStream 被一个循环调用了 200 次。原来是没有做图片缓存,每次滑动都重新解码。
分析技巧:关注「Self Time」列,它表示方法自身执行的时间(不包括子调用)。如果 Self Time 很高,说明这个方法本身就很慢。如果「Children Time」很高,说明它的子调用有问题。
3.4 Method Tracing:代码级别的「慢动作回放」
Method Tracing 是 TraceView 的进阶用法。它不仅能记录方法耗时,还能记录方法参数、返回值、甚至对象分配信息。说白了,就是给代码拍了个「慢动作视频」。
3.4.1 如何开启 Method Tracing
在代码中手动开启:
// 开始追踪
Debug.startMethodTracing("app_trace", 1024 * 1024 * 10); // 10MB 缓冲区
// ... 你的业务代码 ...
// 停止追踪
Debug.stopMethodTracing();
生成的 app_trace.trace 文件可以用 Android Studio 的 Profiler 打开。我建议在关键路径上加上 Method Tracing,比如列表滑动、页面跳转、网络请求等。
注意事项:Method Tracing 的开销很大,尤其是 Instrument 模式。我曾经在低端机上开启 Method Tracing,结果应用直接 ANR 了。建议只在 Debug 版本中使用,并且控制追踪时长在 5 秒以内。
3.4.2 实战:定位「卡顿元凶」
假设你的应用在某个页面打开时卡顿。用 Method Tracing 抓取后,你可能会看到这样的数据:
方法名 | 调用次数 | 总耗时(ms) | 平均耗时(ms)
onCreate | 1 | 350 | 350
- initView | 1 | 200 | 200
- loadLargeImage | 1 | 150 | 150
- initData | 1 | 100 | 100
- queryDatabase | 1 | 80 | 80
看到没?loadLargeImage 和 queryDatabase 是两大耗时点。优化方案:
- 图片加载改为异步 + 缩略图
- 数据库查询改为预加载 + 缓存
优化后,onCreate 的总耗时从 350ms 降到了 80ms。嗯,这就是 Method Tracing 的价值——让你用数据说话,而不是靠猜。
3.5 工具选择指南
最后,我总结一下这几个工具的使用场景:
| 问题类型 | 推荐工具 | 原因 |
|---|---|---|
| UI 卡顿、掉帧 | Systrace / Perfetto | 能看到渲染管线、GPU 调度 |
| CPU 负载高、线程阻塞 | Perfetto | 能看到线程状态、锁竞争 |
| 方法耗时、调用栈分析 | TraceView / Method Tracing | 能看到每个方法的精确耗时 |
| 内存泄漏、对象分配 | Perfetto (heap profiler) | 能看到对象分配栈 |
你想想看,如果你遇到卡顿问题,却用 TraceView 去分析,那就像用显微镜看大象——能看到细节,但看不到全貌。反过来,如果你用 Systrace 去分析一个方法耗时,那就像用望远镜看蚂蚁——能看到轮廓,但看不清细节。工具选对了,问题就解决了一半。
我的工作流:遇到性能问题,先用 Perfetto 看系统级数据,定位到具体线程或模块。再用 TraceView 或 Method Tracing 深入分析具体方法。最后用代码优化 + 二次验证。这套流程帮我解决过上百个性能问题,你可以直接拿来用。
好了,这一章的内容就到这里。下一章我们会聊「内存优化实战」,到时候我会分享一些「血泪史」——比如怎么把 200MB 的内存占用降到 50MB。敬请期待。