Skip to content

iOS 应用启动性能总览:从进程拉起到首帧 ​

应用启动不是一个单一秒数,而是一条从进程建立、运行时初始化、UIKit 生命周期到首帧呈现的时间链。Perfowl 的启动分析采用无侵入黑盒方式,不改包、不注入 SDK、不要求目标 App 具备调试签名;知识库中把启动结果分成三个层次理解:启动主结果、阶段诊断、观测质量。

先看结论

  • App Launch Total 是主指标,由启动首尾两个真实端点决定,不是九阶段耗时求和。
  • 九阶段是可观测诊断模型,用于解释时间花在哪里;并不要求每个 App、每一轮都必须 9/9 有值。
  • Perfowl 当前受控启动属于 process-cold launch:目标进程会被重新创建,但这不等于“设备级绝对冷启动”,也不承诺清空 dyld/page cache 或消除 iOS 系统 prewarming。

iOS App Startup 的端点与阶段观测模型

图:Launch Total 由两个真实端点决定;生命周期阶段用于诊断覆盖度,两者分别维护质量状态。


1. 先区分 Activation、Launch 与 Resume ​

一次用户激活 App,既可能需要创建新进程,也可能只是恢复已有进程:

text
用户激活 App
    │
    ├── 目标进程不存在 → Launch
    │
    └── 目标进程仍存活/挂起 → Resume

Apple 也将 warm / cold launch 描述为一个连续谱,而不是两个绝对状态:系统缓存、依赖页、守护进程和设备内存压力都会影响同一个 App 的启动成本。Perfowl 的 StartupTiming 当前聚焦于需要重新建立目标进程的受控启动,不把后台恢复时间混入 Launch Total。

Apple 参考:


2. Perfowl 的受控 process-cold 语义 ​

Perfowl 启动分析使用 processcontrol 发起一次受控拉起,并保证旧目标进程被替换。这个场景适合做版本回归,因为“目标进程重新创建”这一点是可控的;但它不等价于设备完全冷态。

原因包括:

  • iOS 可能保留动态库、文件页和系统服务缓存;
  • Apple 明确存在 App prewarming:系统可提前创建非运行 App 的进程并加载其依赖库,然后在应用代码执行前挂起;
  • 即使设备重启,系统仍可能在条件允许时执行 prewarming;
  • 因此 KillExisting=true + StartSuspended=false 只能描述为“受控 process-cold”,不能描述成“清空所有系统缓存后的绝对冷启动”。

如果测试目标是“开机后第一次启动”“刚安装后的 first-run”“高内存压力后的启动”,应把它们定义为不同测试场景,不要和稳定 process-cold 轮次混成一个总体分布。


3. 启动结果的三层结构 ​

3.1 Observation Layer:外部生命周期观测 ​

Perfowl 还维护两个轻量观测指标:

  • Process Observed Running
  • Foreground Ready

它们从 Launch Request 到主机观测到目标进程运行/前台的时刻计算,带有轮询误差上界。它们适合回答“进程大约何时起来、何时进入前台”,但不等于首帧,也不能替代 Launch Total。

3.2 Launch Truth:App Launch Total ​

StartupTiming 的核心主结果是:

text
System Interface BEGIN
          │
          │  absolute endpoint span
          ▼
Initial Frame END

即:

text
App Launch Total
= Initial Frame END - System Interface BEGIN

Total 是首尾端点的真实内核时间差。由于 iOS 启动过程存在并行、交叠与条件回调,Total 不是九阶段相加。因此即使某个中间阶段本轮没有被捕获,只要两个端点成立,Total 仍然可以成立。

3.3 Diagnostic Breakdown:九阶段可观测模型 ​

九阶段用于回答“启动时间花在哪里”:

text
Pre-main
  1. System Interface Initialization
  2. Static Runtime Initialization

UIKit / App lifecycle
  3. UIKit Initialization
  4. UIKit Scene Creation
  5. willFinishLaunchingWithOptions()      [条件]
  6. didFinishLaunchingWithOptions()
  7. sceneWillConnectTo()                   [条件]
  8. sceneWillEnterForeground()             [条件]

Presentation
  9. Initial Frame Rendering

其中部分生命周期回调本身就是条件触发。某些 App 的启动路径可能确实不经过对应回调,但不能仅凭“本轮没有看到 signpost”就直接判为 not-applicable:只有独立证据能够证明该阶段本轮不适用时才这样标记,否则保持 missing。无论哪种情况都不能补 0 ms。


4. “首帧完成”不等于“业务完全可用” ​

Perfowl Launch Total 的终点是 Initial Frame END。它衡量的是从系统启动端点到首帧呈现端点的启动链路,不代表:

  • 首页所有网络数据都已返回;
  • 图片、WebView、地图等延迟内容全部加载完成;
  • 所有延迟初始化任务已经结束;
  • 用户已经可以完成某个具体业务动作。

Apple 的性能体系也区分 first draw、optimized first draw、resume 和 extended launch。对于需要在首帧之后继续等待业务准备的 App,应另建业务可用性指标,而不是把首帧之后的工作强行塞进 Launch Total。

Apple 参考:


5. 如何阅读一份 Startup 结果 ​

推荐顺序不是先追求 9/9,而是:

text
1. Launch Total 是否有值?
        ↓
2. Total 是 clean / repaired / missing?
        ↓
3. 本轮捕获了多少阶段(X/9)?
        ↓
4. 哪个真实阶段耗时异常?
        ↓
5. 是否存在 device loss marker / source 异常?

例如:

text
Launch Total = 1.86 s        clean
Phase Coverage = 6/9
3 个条件/未捕获阶段隐藏
Device Lost Marker = 0

这仍然是一份可以用于 Total 回归与已捕获阶段诊断的有效结果。0 个 device loss marker 只表示本轮没有观测到内核丢失标记,不等于整条采集链数学意义上的无损。


6. 阶段过慢时如何初步归因 ​

区域典型异常优先排查
System Interfacedyld / image load 时间上升第三方动态库数量、二进制体积、依赖变化
Static Runtimepre-main 静态初始化上升ObjC +load、C/C++ constructor、全局静态对象
didFinishLaunching主线程同步工作过多SDK 初始化、数据库、同步 I/O、同步网络等待
Scene / UI 建立Window / Root VC 建立慢首屏结构、状态恢复、业务容器装配
Initial Frame首帧显著变慢主线程布局、图片解码、首屏绘制、同步数据读取

阶段值只能说明“时间落在哪个区间”,不能仅凭一个阶段值直接断言某个具体函数就是根因。需要结合 CPU、线程状态、I/O、截图与代码级 Instruments 继续取证。


7. 推荐的启动测试场景 ​

不要把所有启动都称为“冷启动”。建议最少区分:

场景用途是否和稳定 process-cold 合并统计
稳定 process-cold日常版本回归主场景是,单独成组
第一次安装后启动first-run 初始化成本否
开机后首次启动更冷的系统状态否
高内存压力后启动page-in / dependency 重载压力否
Resume后台恢复体验否,属于另一类激活

多轮测试时不要机械丢弃第 1 轮。第 1 轮可以单列为 colder-state observation;稳定 process-cold 再使用后续同条件轮次计算 P50 / P90。


8. 推荐阅读路径 ​

  1. 本页:建立 Launch Total、九阶段和 process-cold 的整体概念。
  2. App Launch Total:启动主结果的公式、Total Provenance 与端点修复语义。
  3. Startup Observation:轻量外部观测指标的公式与误差边界。
  4. Startup Phases:九阶段公式、质量语义与当前真机捕获率证据。
  5. 启动观测与数据完整性:理解 CoreProfile、kdebug 、两遍归因、随机缺失和端点修复。
  6. 启动测试方法与诊断:执行多轮测试、统计回归和缺陷提单。
  7. Startup 技术演进与实验:kdebug/CoreProfile/prewarm 等路线的决策依据与被证伪路线。

Perfowl · Performance Observer