2. 冷启动与热启动定义:区别界定、触发条件、测量起点终点、行业标准
2.1 核心概念辨析
启动耗时是衡量客户端应用/系统性能的关键指标。为了准确定位优化方向并保证测量的一致性,必须首先明确“冷启动”与“热启动”两种启动模式的定义与边界。其核心区别在于进程状态与缓存数据的重用程度。
| 启动类型 | 进程状态 | 缓存/内存数据 | 典型耗时范围 |
|---|---|---|---|
| 冷启动 | 无 | 无(需重新加载) | 700ms ~ 2000ms+ |
| 热启动 | 存在(后台存活) | 完整保留 | 100ms ~ 300ms |
| 温启动* | 新创建(但有一定缓存) | 部分保留 | 300ms ~ 700ms |
温启动说明:部分行业标准将“温启动”单独成类,指进程被杀但内存缓存(如图片文件缓存、View 对象池)被部分恢复的场景。在本章中,温启动可视为冷启动的后半段优化状态,其测量逻辑遵循冷启动规则。
2.2 触发条件界定
明确触发条件直接决定了测试场景的构造方式。以下是两种启动模型的严格界定:
- 冷启动触发条件:
- 应用进程完全不存在于后台进程列表。
- 系统或设备首次开机后首次启动应用。
- 用户通过“设置-应用-强行停止”后重新拉起。
- 开发者主动调用
adb shell am force-stop命令。
- 热启动触发条件:
- 用户按下 Home 键后再次点击应用图标(未 swipe 清除)。
- 通过通知栏快速跳转回应用。
- 应用未被系统/用户主动杀死,且未触发内存回收。
避坑提示:在性能压测时,如果连续执行
adb shell am start 而不执行 force-stop,后续启动会全部变成热启动数据,导致报告失真。必须严格按照预定义的触发条件构造场景。2.3 测量起点与终点
统一测量窗口是横向对比不同版本或竞品的基础。业界普遍接受的分段测量标准如下:
| 阶段 | 时间点 | 典型 API / 信号 |
|---|---|---|
| 起点 | 用户主动触发起动动作 | onCreate() 开始 / ams 启动事件 |
| 终点(冷启动) | 首帧画面完全渲染 + 主视图内容填充完毕 | onWindowFocusChanged / View.draw 首次完成 |
| 终点(热启动) | 最后一个界面绘制结束(无异步 loading) | onResume + ReportFullyDrawn |
代码示例:Android 端手动标记冷启动终点
// 在目标 Activity 的 onWindowFocusChanged 中埋点
public class MainActivity extends AppCompatActivity {
private static final String TAG = "ColdStartup";
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
// 冷启动终点——首帧且焦点就绪
long startupEnd = SystemClock.uptimeMillis();
Log.d(TAG, "ColdStartup_End: " + startupEnd);
// 注入到 MetricKit 或自定义统计系统
}
}
}
2.4 行业标准与阈值参考
各主流平台与自动化测试框架对启动耗时的达标线有明确约定:
- Android(Vitals / Fireperf / Macrobenchmark):冷启动总耗时 ≤ 2.0s(首帧),≤ 1.5s(内容就绪)。
- iOS(MetricKit / XCTest):冷启动 tti(time to interactive)≤ 2.0s,热启动 ≤ 1.0s。
- Web / SPA:FCP(First Contentful Paint)≤ 1.8s,LCP ≤ 2.5s。
- 行业通用“秒开”标准:冷启动 ≤ 1.5s,热启动 ≤ 0.5s。
关键结论:在自动化流水线中,必须将 95 分位耗时(P95)作为截断标准,而不是均值。P95 能更真实反映用户端尾部体验。
2.5 启动类型区别流程框架图
下图描述了冷启动与热启动在全生命周期中的路径差异、测量节点以及优化目标区域:
2.6 常见错误与调试建议
- 错误1:起点未与用户动作对齐。解决:使用
adb shell am start -W输出ThisTime / TotalTime作为冷启动基准,或用 Android Bugreport 的AppStartup段。 - 错误2:热启动测量未过滤中间页面栈。解决:热启动测试前,确保应用处于首屏/目标屏而非深链路页面,否则终点判定会偏差。
- 错误3:忽略异步初始化对终点的影响。解决:业务自定义
reportFullyDrawn()回调,确保所有关键组件加载完毕。
调试命令例子(Windows/macOS/Linux 均可用):
# 冷启动测量(强制重启 + 启动 + 打印耗时)
adb shell am force-stop com.example.app
adb shell am start -W com.example.app/.MainActivity | grep -E "ThisTime|TotalTime"
# 热启动测量(仅执行启动命令)
adb shell am start -W com.example.app/.MainActivity | grep -E "ThisTime|TotalTime"
以上命令得到的 TotalTime 即从起点到 onWindowFocusChanged 的耗时,可作为标准化冷/热启动测量数据。