欢迎访问我的博客原文
文章目录
当 App 中的业务模块越来越多、越来越复杂,集成了更多的三方库,App 启动也会越来越慢,因此我们希望能在业务扩张的同时,保持较优的启动速度,给用户带来良好的使用体验。
热启动与冷启动
当用户按下 home 键,iOS App 不会立刻被 kill,而是存活一段时间,这段时间里用户再打开 App,App 基本上不需要做什么,就能还原到退到后台前的状态。我们把 App 进程还在系统中,无需开启新进程的启动过程称为热启动。
而冷启动则是指 App 不在系统进程中,比如设备重启后,或是手动杀死 App 进程,又或是 App 长时间未打开过,用户再点击启动 App 的过程,这时需要创建一个新进程分配给 App。我们可以将冷启动看作一次完整的 App 启动过程,本文讨论的就是冷启动的优化。
冷启动概要
WWDC 2016 中首次出现了 App 启动优化的话题,其中提到:
- App 启动最佳速度是400ms以内,因为从点击 App 图标启动,然后 Launch Screen 出现再消失的时间就是400ms;
- App 启动最慢不得大于20s,否则进程会被系统杀死;(启动时间最好以 App 所支持的最低配置设备为准。)
冷启动的整个过程是指从用户唤起 App 开始到 AppDelegate 中的 didFinishLaunchingWithOptions
方法执行完毕为止,并以执行 main()
函数的时机为分界点,分为 pre-main
和 main()
两个阶段。
也有一种说法是将整个冷启动阶段以主 UI 框架的 viewDidAppear
函数执行完毕才算结束。这两种说法都可以,前者的界定范围是 App 启动和初始化完毕,后者的界定范围是用户视角的启动完毕,也就是首屏已经被加载出来。
注意:这里很多文章都会把第二个阶段描述为 main 函数之后,个人认为这种说法不是很好,容易让人误解。要知道 main 函数在 App 运行过程中是不会退出的,无论是 AppDelegate 中的
didFinishLaunchingWithOptions
方法还是 ViewController 中的viewDidAppear
方法,都还是在 main 函数内部执行的。
pre-main 阶段
pre-main
阶段指的是从用户唤起 App 到 main()
函数执行之前的过程。
查看阶段耗时
我们可以在 Xcode 中配置环境变量 DYLD_PRINT_STATISTICS
为 1(Edit Scheme → Run → Arguments → Environment Variables → +
)。
这时在 iOS 10 以上系统中运行一个 TestDemo,pre-main
阶段的启动时间会在控制台中打印出来。
Total pre-main time: 354.21 milliseconds (100.0%)
dylib loading time: 25.52 milliseconds (7.2%)
rebase/binding time: 12.70 milliseconds (3.5%)
ObjC setup time: 152.74 milliseconds (43.1%)
initializer time: 163.24 milliseconds (46.0%)
slowest intializers :
libSystem.B.dylib : 7.98 milliseconds (2.2%)
libBacktraceRecording.dylib : 13.53 milliseconds (3.8%)
libMainThreadChecker.dylib : 41.11 milliseconds (11.6%)
TestDemo : 88.76 milliseconds (25.0%)
如果要更详细的信息,就设置 DYLD_PRINT_STATISTICS_DETAILS
为 1。
total time: 1.6 seconds (100.0%)
total images loaded: 388 (381 from dyld shared cache)
total segments mapped: 23, into 413 pages
total images loading time: 805.78 milliseconds (48.6%)
total load time in ObjC: 152.74 milliseconds (9.2%)
total debugger pause time: 780.26 milliseconds (47.1%)
total dtrace DOF registration time: 0.00 milliseconds (0.0%)
total rebase fixups: 54,265
total rebase fixups time: 20.77 milliseconds (1.2%)
total binding fixups: 527,211
total binding fixups time: 513.54 milliseconds (31.0%)
total weak binding fixups time: 0.31 milliseconds (0.0%)
total redo shared cached bindings time: 521.93 milliseconds