第2章:启动流程分析——冷启动、热启动、温启动
说到应用启动速度,很多人上来就盯着代码优化。但我个人的习惯是——先搞清楚你的App到底处在哪种启动状态。因为冷启动、热启动、温启动,这三者的优化思路完全不同。你想想看,一个已经跑在内存里的进程,和一个刚被系统拉起来的进程,耗时差了几倍甚至十几倍。如果不区分场景,优化就是在打乱拳。
这一章我们就来拆解这三种启动流程。我会结合之前做性能监控项目时踩过的坑,告诉你每种启动的耗时大头在哪,以及怎么针对性监控。
冷启动:从零开始的“完全体”链路
冷启动,说白了就是应用进程还没创建,系统需要从头拉起一个进程。这是耗时最长的启动类型。整个过程大致分几步:
- 系统fork进程——Zygote孵化出一个新的App进程。
- 加载并初始化Application——包括attachBaseContext、onCreate,以及ContentProvider的创建和初始化。
- 创建并初始化MainActivity——走构造函数、onCreate, onStart, onResume。
- 布局渲染与首帧显示——测量、布局、绘制、交换缓冲区,直到看到第一帧。
这里最容易被忽视的是ContentProvider的初始化。我记得有一次线上监控发现冷启动突然变慢200ms,查了一整天,最后发现是第三方SDK在ContentProvider里做了网络请求。嗯,这种操作真的很坑。
冷启动的总耗时,从用户点击图标到首帧完成,通常在1~3秒左右,视机型而异。优化的核心思路是:延迟初始化 + 异步加载。
冷启动关键指标:
- 进程创建到Application.onCreate开始时间
- Application.onCreate执行耗时
- Activity.onCreate总耗时
- 首帧绘制延迟
热启动:几乎“秒开”的体验
热启动,指应用进程还在后台上,Activity虽然被销毁但进程活着。用户再次打开App时,系统直接走Activity的重新创建流程,Application和ContentProvider都不需要重新初始化。
热启动耗时通常在100~300ms之间,主要时间花在:
- Activity的onCreate、onStart、onResume
- 布局渲染
因为大部分数据已经缓存在内存里(比如图片缓存、网络接口的本地数据),所以热启动给人的感觉就是“秒开”。但这里有个陷阱——如果你在Activity的onCreate里做了大量重量级初始化,比如解码大图、加载数据库,热启动也会变慢。
我自己的经验是:把热启动场景下的Activity初始化代码,和冷启动场景分开判断。比如通过isColdStart标志位,冷启动时加载全量配置,热启动时只加载视图必需的数据。
温启动:介于两者之间的中间态
温启动,听名字就知道是个折中情况。进程还在,但Activity已经被系统回收了(比如内存不足时系统回收了Activity但保留了进程)。这时候用户重新打开App,系统需要:
- 重新创建Activity
- 走Activity生命周期
- 但Application和ContentProvider不需要重新初始化
温启动的耗时通常在300~800ms之间。它的优化方向基本和热启动一致,但有一个额外的点——onSaveInstanceState恢复状态。如果你在Activity被回收前没有保存好关键UI状态,温启动时就需要重新获取数据,耗时就会增加。
注意:温启动时如果磁盘缓存失效或网络请求超时,体验会突然劣化。建议在恢复状态时增加超时兜底逻辑,比如先展示缓存数据,异步刷新。
三种启动流程对比表
| 启动类型 | 进程是否存在 | Activity是否存在 | Application初始化 | 典型耗时 | 优化重点 |
|---|---|---|---|---|---|
| 冷启动 | 否 | 否 | 需要 | 1~3秒 | 延迟初始化、异步加载、ContentProvider瘦身 |
| 温启动 | 是 | 否 | 不需要 | 300~800ms | 恢复状态优化、避免重量级onCreate |
| 热启动 | 是 | 被回收(后台内存不足时)或尚未被回收 | 不需要 | 100~300ms | Activity轻量化、避免多余的初始化 |
我的一个实用技巧:在性能监控SDK的启动阶段打上标记,比如用进程启动时的SystemClock.elapsedRealtime(),结合ActivityLifecycleCallbacks记录每个Activity的生命周期日志。这样你就能从日志里一眼看出当前是哪种启动状态。
用一张图捋清三种启动的关系
下面这张流程图展示了一个App从点击图标到首帧出现的完整路径。注意看三条分支的颜色:冷启动走红色线路(最长),温启动走橙色,热启动走绿色(最短)。
从图中你能立刻看懂三个关键点:
- 冷启动的路径最长,必经Application和ContentProvider初始化,这是优化主战场。
- 热启动几乎跳过了所有初始化,仅走Activity创建和渲染,所以优化的空间很小。
- 温启动的Activity回收可能携带保存的状态数据,如果恢复逻辑写得好,耗时可接近热启动。
顺便提一句,我在做动态化交付的时候,发现一个容易被忽略的现象:很多团队只盯着冷启动优化,却忽略了温启动场景下的状态恢复耗时。我曾经在一个项目里遇到用户抱怨“切后台再回来经常白屏几秒”,最后查出来是onRestoreInstanceState里做了网络请求。这种问题其实很好修——把恢复逻辑做成异步加缓存兜底就行了。
好了,这一章我们把三种启动的流程和优化方向理清了。接下来在监控方案里,你需要明确区分当前是哪种启动类型,才能对症下药。下一部分我们会聊聊如何用工具精准记录这些阶段的耗时。