三、性能分析工具(一):系统自带工具入门
做性能优化,第一步永远是「测量」。没有数据,一切优化都是瞎猜。
我见过太多开发同学,一上来就凭感觉改代码。改完一看,启动时间反而更长了。说白了,你都不知道瓶颈在哪,怎么改?
这章咱们就聊聊三端最核心的系统自带工具:Instruments(iOS)、Systrace/Perfetto(Android)、Chrome DevTools(Web)。
3.1 宏观视角:三端工具全景图
先上一张图,帮大家建立整体认知。这不是什么高大上的设计图,就是我自己梳理的工具使用脉络。
你想想看,三个平台的工具虽然名字不同,但核心逻辑是相通的:记录时间线 -> 分析线程/进程行为 -> 定位耗时热点。掌握了这个通用逻辑,换平台只是换了个操作界面而已。
3.2 iOS:Instruments 入门
Instruments 是 Xcode 自带的性能分析工具。我个人习惯用 Time Profiler 和 System Trace 这两个模板来排查启动问题。
快速上手:分析 App 启动
- 打开 Xcode,连接真机设备(不建议用模拟器,数据不准)。
- 选择
Product > Profile,或按Command + I。 - 在弹出的模板选择窗口中,选 Time Profiler。
- 点击录制的红色圆点,然后在设备上杀掉 App 重新打开。
- 等 App 完成首屏渲染后,停止录制。
读数据:我重点关注两个阶段
- pre-main 阶段:从点击图标到 main() 函数执行。这段时间主要花在 dyld 动态链接、ObjC 类注册、静态初始化器上。Instruments 里的 "App Launch" 模板可以直观看到这部分。
- main() 之后到首帧:这个阶段主要看你的 UI 初始化、网络请求、数据库读取等逻辑。
我在项目中遇到过一个问题:某个版本的 App 启动突然慢了 500ms。用 Instruments 一抓,发现是某个第三方 SDK 的 +load 方法里做了大量计算。说白了,就是动态链接阶段被拖慢了。解决办法很简单,把那个 SDK 改成懒加载。
3.3 Android:Systrace / Perfetto 入门
Android 这边,老项目可能还在用 Systrace,但 Google 已经明确推荐用 Perfetto 了。我个人建议直接用 Perfetto,功能更强,UI 也更现代。
快速上手:用 Perfetto 抓取启动 Trace
- 手机上安装 Perfetto 的客户端(或者直接用命令行)。
- 配置一个 Trace 配置文件,比如针对启动场景,我们关心主线程、RenderThread、SurfaceFlinger。
# 一个简单的 Perfetto 配置示例
buffers: {
size_kb: 102400
}
data_sources: {
config {
name: "linux.ftrace"
ftrace_config {
ftrace_events: "sched/sched_switch"
ftrace_events: "power/suspend_resume"
ftrace_events: "binder/binder_transaction"
}
}
}
然后通过命令行启动录制:
adb shell perfetto -c /data/local/tmp/config.pbtxt -o /data/misc/perfetto-traces/trace.perfetto-trace
抓取完成后,把 trace 文件 pull 出来,传到 ui.perfetto.dev 上打开。
M 键就可以标记。然后看底部的 "Critical Path" 分析,它会自动告诉你哪一段耗时最长。
我常用的分析技巧
- 看颜色:主线程(通常是
tid=1)的状态通过颜色区分。绿色 = Running,蓝色 = Runnable,红色 = Sleeping/Blocked。如果红色特别多,说明线程在等锁或等 I/O。 - 看 SurfaceFlinger:如果 App 启动过程中表面 Flinger 出现丢帧(jank),可能是 UI 线程耗时太长,导致掉帧。
- 重点关注跨进程调用:Binder 调用在 trace 里有清晰的标识。我曾经遇到过一个问题:冷启动时主线程频繁调用 Binder 去获取系统服务,每次 wait 几十毫秒,累计下来就多了。
3.4 Web:Chrome DevTools 入门
Web 启动优化的工具相对容易上手,但很多人只用它看网络请求,忽略了 Performance 面板的强大能力。
快速上手:录制页面加载过程
- 打开 Chrome,按
F12进入 DevTools。 - 切换到 Performance 面板。
- 点击左上角的录制按钮(或按
Ctrl+E)。 - 刷新页面(不用手动刷新,可以勾选 "Screenshots" 方便后面看画面)。
- 等待页面完全加载后,停止录制。
我怎么读 Performance 的火焰图
- 看 "Main" 轨道:这是主线程的活动。如果看到一堆黄色的 "Task" 块,并且很长,说明有长任务阻塞了主线程。
- 看 "Timings" 轨道:这里会显示 FP、FCP、LCP 等关键指标。我习惯先看 LCP,因为它是「用户感知加载完成」的最重要指标。
- 看 "Network" 轨道:重点关注哪些资源的下载时间过长,或者有没有串行加载的请求。
我记得有一次,一个 H5 页面启动特别慢。用 Performance 一录,发现 LCP 之前的瀑布图里有一个 500k 的 JSON 数据请求。那个 JSON 是关键渲染路径上的资源,但它的服务器响应时间居然有 2 秒。说白了,后端接口慢,前端怎么优化都没用。我当时直接去找后端同学优化了接口,LCP 瞬间从 4 秒降到 1.5 秒。
3.5 三端工具对比总结
为了方便你快速回忆,我把三端工具的核心对比整理成了表格。你可以在实际选型时参考。
| 对比维度 | iOS (Instruments) | Android (Perfetto) | Web (Chrome DevTools) |
|---|---|---|---|
| 最佳场景 | 启动耗时分析,线程调用堆栈 | 主线程卡顿分析,跨进程调用 | 资源加载分析,LCP/FCP 归因 |
| 核心数据 | CPU 采样 + 系统追踪 | Ftrace 事件 + 内核日志 | JS 执行时间 + 渲染事件 |
| 上手难度 | ★★★☆☆(需要熟悉 Xcode) | ★★★☆☆(命令行门槛) | ★★☆☆☆(UI 直观) |
| 我最常用的场景 | 检查 +load 方法和动态库 | 分析 Binder 调用和锁竞争 | 查找长任务和未使用代码 |