第28章:Logcat 与 Trace:结合 Systrace 进行深度性能分析
性能分析,说白了就是找卡顿、追内存、揪CPU。
Logcat 能告诉你「发生了什么」,但很难告诉你「为什么这么慢」。这时候,Systrace 就派上用场了。我个人习惯把 Logcat 和 Systrace 当成一对搭档——一个负责记录事件,一个负责绘制时间线。
28.1 为什么需要 Systrace?
Logcat 的输出是线性的文本流。你看到一行日志说「onClick 耗时 500ms」,但你不知道这 500ms 到底花在了哪里。是主线程被阻塞了?还是 Binder 调用卡住了?
Systrace 能回答这个问题。它从内核层、系统服务层、应用层同时抓取数据,生成一张时间轴图。你可以看到每个线程在做什么,什么时候被调度,什么时候在等锁。
核心区别:
- Logcat:记录事件日志,适合排查逻辑错误
- Systrace:记录时间线,适合排查性能瓶颈
我在项目中遇到过一个问题:某个页面滑动掉帧,Logcat 里没有任何异常日志。但 Systrace 一开,立马发现是 GPU 渲染超时,主线程在等 vsync 信号。嗯,这种问题光靠 Logcat 根本看不出来。
28.2 如何同时抓取 Logcat 和 Systrace?
你可以在抓取 Systrace 的同时,把 Logcat 也带上。这样,时间线上就能看到对应的日志事件。
# 抓取 10 秒的 Systrace,同时包含 Logcat 标签 "MyApp"
python systrace.py -t 10 -a com.example.myapp -o trace.html \
--logcat="*:V"
这个命令会生成一个 HTML 文件。打开后,你会在时间轴下方看到 Logcat 面板。点击某个日志条目,时间轴会自动定位到对应的时间点。
我的习惯:在关键代码路径上加自定义 Trace 标签,然后在 Logcat 里打印同样的 tag。这样在 Systrace 里一眼就能找到对应的区间。
28.3 在代码中埋 Trace 点
光靠系统自带的 Trace 点不够细。你需要在关键函数里手动加 Trace 标记。
import android.os.Trace;
public void loadData() {
Trace.beginSection("loadData");
try {
// 你的业务逻辑
fetchFromNetwork();
parseJson();
updateUI();
} finally {
Trace.endSection();
}
}
抓取 Systrace 时,加上 -a com.example.myapp 参数,就能看到这些自定义标签。
我曾经在某个项目里,发现一个列表加载慢。加了 Trace 后才发现,问题不在网络请求,而在 parseJson() 里有个 O(n²) 的循环。你看,没有 Trace 点,你根本不知道瓶颈在哪。
28.4 结合 Logcat 定位具体原因
Systrace 告诉你「哪里慢」,Logcat 告诉你「为什么慢」。两者结合,效果翻倍。
举个例子:
- Systrace 显示主线程在
onBindViewHolder里卡了 200ms - Logcat 里看到
W/ImageLoader: decode耗时 180ms - 结论:图片解码太慢,需要优化缓存策略
注意:Systrace 抓取期间,Logcat 的日志量可能会很大。建议只过滤你关心的 tag,否则生成的 HTML 文件会非常庞大,打开都费劲。
28.5 实战:分析启动速度
应用启动慢,是性能优化的重灾区。我一般这么操作:
- 在 Application.onCreate() 和 MainActivity.onCreate() 里加 Trace 标签
- 在关键初始化方法里加 Logcat 日志,记录耗时
- 同时抓取 Systrace 和 Logcat
- 分析时间轴,找到最耗时的阶段
// Application 中
@Override
public void onCreate() {
Trace.beginSection("Application.onCreate");
super.onCreate();
initSDK();
initDB();
Trace.endSection();
}
// 日志输出
Log.d("AppStart", "initSDK 耗时: " + (end - start) + "ms");
打开 Systrace 后,你会看到类似这样的时间线:
从这张图里,你能直观地看到:
- Application.onCreate 占了 200ms,其中 initDB 是瓶颈
- 网络请求和 UI 初始化是并行的,但渲染线程在第一帧之后出现了掉帧
- Logcat 日志和 Trace 时间线完美对应
28.6 常见坑与避坑指南
我踩过不少坑,分享几个给你:
- Trace 标签嵌套错误:beginSection 和 endSection 必须成对出现,且不能交叉。我曾经在 try-finally 里漏了 endSection,导致后面所有 Trace 都乱了。
- Logcat 过滤太宽:抓取时如果不过滤,日志量可能上百万条。Systrace 打开后直接卡死。建议只抓
*:I或指定 tag。 - 时间不同步:如果 Logcat 和 Systrace 的时间戳不是同一个时钟源,对不上。好在 Android 系统已经统一了,但如果你用 adb logcat -v time 抓的日志,时间格式是 human readable,没法直接对齐。建议用
-v epoch输出时间戳。
我的建议:在开发阶段就养成加 Trace 标签的习惯。不要等到性能出问题了再补。就像写日志一样,Trace 标签也是代码的一部分。
28.7 总结
Logcat 和 Systrace 不是二选一的关系。它们是互补的。Logcat 告诉你「发生了什么」,Systrace 告诉你「什么时候发生的、花了多久」。两者结合,你才能完整地理解一个性能问题。
嗯,说白了就是:Logcat 是文字版,Systrace 是图形版。你写代码时多埋几个 Trace 点,抓数据时带上 Logcat,分析时两边对照着看。这套组合拳打下来,大部分性能问题都藏不住。
公众号:蓝海资料掘金营,微信deep3321