OC底层原理33:启动优化(二)优化建议
冷启动和热启动
启动的过程一般是指 从用户点击APP图标
到 进入到APP页面
的过程,一般在iOS开发中分为 冷启动
和 热启动
冷启动
:用户将设备重启
或者是手动kill掉APP进程
,又或者是APP长时间未打开过
,当用户点击启动APP图标的过程,这时需要创建一个新的进程
分配给APP,并且内存中不包含任何数据
,必须从磁盘中载入数据到内存中的过程。热启动
:用户在使用APP过程中,按下Home键
,APP不会立即被kill掉,而是存活一段时间,这段时间里用户再打开APP,此时APP还在退到后台前的状态,APP进程还在系统中,无需开启新的进程,APP也不会重新加载数据到内存中的过程。
启动优化概念
- WWDC
2016
中首次出现了APP启动优化的话题,其中提到:
App启动最佳速度是400ms以内
,因为从点击App图标启动,然后Launch Screen
出现再消失的时间就是400ms。App启动最慢不得大于20s
,否则进程会被系统杀死
- 我们这里所说的启动优化,一般是指
冷启动
情况下的启动优化,是指用户唤起App开始到AppDelegate
中的didFinishLaunchingWithOptions
方法执行完毕为止,并以main()
函数为分界点,分为pre-main
和main()
两个阶段:
pre-main
阶段:是指从用户唤起App到main()
函数执行之前的过程main()
阶段:是指main()
函数开始执行到didFinishLaunchingWithOptions
方法执行结束的过程
- 所以,
pre-main() + main()
的过程就是从用户点击App图标到用户能看到主界面的过程,即需要优化的部分。
pre-main()启动优化
我们在前面 OC底层原理15:dyld源码分析 中,已经了解了
dyld
的加载流程,pre-main()
阶段的启动时间
就是dyld加载过程的时间
针对
pre-main()
阶段的启动时间,苹果提供了APP启动时间检测方法,在Product -> Scheme -> Edit Scheme -> Environment Variables
点击+
号添加环境变量DYLD_PRINT_STATISTICS
设为1
,如下图:
- 然后运行,以下是
手机型号iPhone11 14.4.2
启动的我目前正在开发的电商项目的pre-main()
时间:
- 如果想要更加详细的信息,就设置
DYLD_PRINT_STATISTICS_DETAILS
为1
,得到以下信息:
说明
1pre-main
阶段总共用时1.3s
2dylib loading time
(动态库耗时):主要是加载动态库,用时336.24ms
3rebase/binding time
(偏移修正/符号绑定耗时),耗时61.26ms
3.1rebase
(偏移修正):任何一个App生成的二进制文件,在二进制文件内部所有的方法、函数调用,都有一个地址,这个地址是在当前二进制文件中的偏移地址
。一旦在运行时刻(即运行到内存中),每次系统都会 随机分配一个ASLR(Address Space Layout Randomization,赋值空间布局随机化)
地址值(是一个安全机制,会分配一个随机的数值,插入在二进制文件的开头),例如,二进制文件中有一个test方法,偏移值是 0x001,而随机分配的ASLR
是0x1000
,如果想访问test方法,其内存地址(即真是地址)变为ASLR+偏移值 = 运行时确定的内存地址(即0x1000 + 0x0001 = 0x1001)
3.2binding
(绑定):例如 NSLog方法,在编译时期 生成的mach-o文件中
,会创建一个符号!NSLog
(目前指向一个随机的地址),然后在运行时(从磁盘加载到内存中,是一个镜像文件),会将真正的地址给符号(即在内存中将地址与符号进行绑定,是dyld
做的,也称为动态库符号绑定
),一句话概括:绑定就是给符号赋值的过程
4Objc setup time
(OC类注册的耗时):OC
类越多,越耗时
5initializer time
:(执行load和构造函数的耗时)
- 针对这几部,有以下几点优化建议:重点面试题
尽量
少用外部动态库
,苹果官方建议自定义的动态库最好不要超过6个
,如果超过6个,需要合并
动态库减少
OC
类,因为类越多,越耗时将不必须在
+load
方法中做的事情延迟到+initialize
中,尽量不要用C++
虚函数如果是Swift,尽量使用
struct
main 函数阶段的优化
在
main
函数之后的didFinishLaunching
方法中,主要是执行了各种业务,有很多并不是必须在这里执行的,这种业务我们可以采取延迟加载
,防止影响启动时间在
didFinishLaunching
中的业务主要分为三个阶段
- 【第一类】初始化第三方sdk
- 【第二类】App运行环境配置
- 【第三类】自己工具类的初始化等
main
函数阶段的优化建议主要有以下几点:重点面试题
减少启动初始化的流程,
能懒加载的懒加载,能延迟的延迟,能放后台初始化的放后台,尽量少占用主线程的启动时间
优化代码逻辑,去除非必须的代码逻辑,减少每个流程的消耗时间
启动阶段能
使用多线程
来初始化的,就使用多线程尽量
使用纯代码
来进行UI框架的搭建,尤其是主UI框架,例如UITabBarController
,尽量避免使用Xib或者StoryBoard,相比纯代码而言,这种更耗时删除废弃类、方法
- Post title:OC底层原理33:启动优化(二)优化建议
- Post author:张建
- Create time:2021-05-11 15:19:40
- Post link:https://redefine.ohevan.com/2021/05/11/OC底层原理/OC底层原理33:启动优化(二)优化建议/
- Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.