冷启动优化:从点击图标到首帧
2026/8/9大约 4 分钟性能与稳定性Android 14冷启动首帧性能优化
冷启动优化:从点击图标到首帧
上一章看了帧时间线。这一章回答:冷启动从点击图标到首帧经过哪些阶段,每段能省什么, 怎么量化与验证?
冷启动包含 AMS 发起进程创建、Zygote fork、Application 与首个 Activity 初始化以及首帧 提交。Displayed 描述首帧可见,ReportFullyDrawn 更适合标记业务内容达到可用状态。
首帧与完全可用是两个里程碑
| 常见误解 | 正确理解 |
|---|---|
| 冷启动慢就是 Application.onCreate 慢 | Application 只是其中一段,进程创建、首 Activity 初始化同样关键 |
| 优化启动就是“少写点代码” | 要按时间线定位哪段超预算,再针对性优化 |
| 首帧出来就算启动完成 | 首帧可见与用户可交互(ReportFullyDrawn)是两个里程碑 |
核心结论
- 主链:点击 → AMS 启动流程 → Zygote fork 进程 → ActivityThread → Application → 首 Activity 创建 → measure/layout/draw → 首帧。
- 常用里程碑:首帧可见、
ReportFullyDrawn(完全可交互)。 - 高频耗时来源:类加载与初始化、dex/基线配置、首屏布局、资源解码、I/O。
- 量化方式:
am start -W、dumpsys gfxinfo、Perfetto 启动轨道。 - 优化原则:按时间线分段,先量化再优化,改一处测一处。
冷启动主链
逐步解释:
- AMS:解析 Intent、找到 Activity、决定启动方式。
- fork:Zygote 创建应用进程(见 Zygote 与写时复制)。
- ActivityThread:主线程与 Looper 就绪。
- Application:全局初始化,越少越好。
- Activity:创建、布局、首绘。
- 里程碑:首帧可见 → 完全可交互。
常见的省钱点
| 阶段 | 常见耗时 | 优化方向 |
|---|---|---|
| 进程创建 | fork 后的初始化 | 减少 Application 全局初始化 |
| 类加载 | 首次加载慢 | 基线配置(baseline profile)、延迟初始化 |
| 首屏 | 布局重、资源大 | 精简首屏层级、延迟非关键资源 |
| I/O | 启动时读文件 | 异步化、缓存、减少主线程 I/O |
优化前先用时间线确认瓶颈在哪段,避免“优化了不痛的环节”。
源码证据
阅读目标:确认启动完成回调与量化入口。
正文指针:Activity.java reportFullyDrawn();ActivityManagerService.java 的启动 计时;am start -W 输出。
// Activity.java(伪代码,行号以 r75 为准)
public void reportFullyDrawn() {
// 告知系统内容已完全绘制
}这段代码证明: 首帧可见与完全绘制是两个显式里程碑;系统据此统计启动耗时, 开发者应在内容真正可用后调用 reportFullyDrawn。
验证与排障
环境:开发设备或模拟器;以下命令不需要 root。
adb shell am start -W -n <包名>/<Activity>
adb shell dumpsys gfxinfo <包名>
adb shell perfetto -o /data/misc/perfetto-traces/trace.perfetto-trace \
-t 15s sched freq idle atrace am wm view appam start -W 给 TotalTime/WaitTime;gfxinfo 看帧数据;Perfetto 看启动轨道。优化前后 用同一命令对比,结论才有说服力。
常见误区
- “只看 Application.onCreate 就行”:启动是整条链,先量化。
- “首帧等于可用”:还有 ReportFullyDrawn 里程碑。
- “优化启动就是删代码”:可能是 I/O、布局或调度问题。
- “一次优化一劳永逸”:设备、系统版本、后台负载都会影响结果。
延伸问题
- 热启动与冷启动的差异在哪里?
- 基线配置(baseline profile)如何加速冷启动?
- 启动时闪白屏/黑屏是怎么产生的,如何优化?
- 系统低内存时冷启动为何更慢?
源码入口
| 文件 | 关键位置 | 作用 |
|---|---|---|
Activity.java | reportFullyDrawn() | 完全绘制回调 |
ActivityManagerService.java | 启动计时 | 启动流程 |
Zygote.java | fork | 进程创建 |
am start -W | 命令行 | 量化入口 |
公共路径:frameworks/base/core/java/android/app/ 与 frameworks/base/services/core/java/com/android/server/am/。行号以 r75 检索为准。
启动或运行期的调度与锁等待,见 CPU 与线程问题。