2. 冷启动与热启动定义:区别界定、触发条件、测量起点终点、行业标准

2.1 核心概念辨析

启动耗时是衡量客户端应用/系统性能的关键指标。为了准确定位优化方向并保证测量的一致性,必须首先明确“冷启动”与“热启动”两种启动模式的定义与边界。其核心区别在于进程状态与缓存数据的重用程度。

启动类型 进程状态 缓存/内存数据 典型耗时范围
冷启动 无 无(需重新加载) 700ms ~ 2000ms+
热启动 存在(后台存活) 完整保留 100ms ~ 300ms
温启动* 新创建(但有一定缓存) 部分保留 300ms ~ 700ms
温启动说明:部分行业标准将“温启动”单独成类,指进程被杀但内存缓存(如图片文件缓存、View 对象池)被部分恢复的场景。在本章中,温启动可视为冷启动的后半段优化状态,其测量逻辑遵循冷启动规则。

2.2 触发条件界定

明确触发条件直接决定了测试场景的构造方式。以下是两种启动模型的严格界定:

  • 冷启动触发条件:
    1. 应用进程完全不存在于后台进程列表。
    2. 系统或设备首次开机后首次启动应用。
    3. 用户通过“设置-应用-强行停止”后重新拉起。
    4. 开发者主动调用 adb shell am force-stop 命令。
  • 热启动触发条件:
    1. 用户按下 Home 键后再次点击应用图标(未 swipe 清除)。
    2. 通过通知栏快速跳转回应用。
    3. 应用未被系统/用户主动杀死,且未触发内存回收。
避坑提示:在性能压测时,如果连续执行 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 启动类型区别流程框架图

下图描述了冷启动与热启动在全生命周期中的路径差异、测量节点以及优化目标区域:

冷启动与热启动路径对比及测量节点图 应用启动全生命周期 进程是否存在? 冷启动路径 新创建进程 | 无缓存数据 起点: onCreate() 开始 终点: 首帧渲染 + 内容填充 热启动路径 复用已有进程 | 缓存完整 起点: Activity.onResume() 终点: 最后一帧绘制完成 行业标准化测量标准 起点一致性 | 终点判定规则 | P95 截断阈值 温启动按冷启动逻辑测量

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 的耗时,可作为标准化冷/热启动测量数据。