iOS App启动优化
iOS启动可分为冷启动和热启动两种
冷启动:app为kill状态下点击app启动
热启动:app启动后按下home在短时间内启动
冷启动
既然是优化那就要弄明白在哪些地方需要优化、可以优化,这个时间到底消耗在哪里.
先检测下App在运行main
函数之前用了多长时间.
在scheme编辑页面 edit scheme -> Run -> Arguments -> environment Variables 添加DYLD_PRINT_STATISTICS
环境变量的Value值设置为1
.
运行App在console中可以看到以下相关的启动日志信息
Total pre-main time: 1.8 seconds (100.0%)
dylib loading time: 205.99 milliseconds (10.9%)
rebase/binding time: 125.12 milliseconds (6.6%)
ObjC setup time: 572.07 milliseconds (30.4%)
initializer time: 976.39 milliseconds (51.9%)
slowest intializers :
libSystem.B.dylib : 38.28 milliseconds (2.0%)
libBacktraceRecording.dylib : 55.36 milliseconds (2.9%)
libMainThreadChecker.dylib : 183.53 milliseconds (9.7%)
libglInterpose.dylib : 412.82 milliseconds (21.9%)
libMTLInterpose.dylib : 141.20 milliseconds (7.5%)
vendingMachine : 99.32 milliseconds (5.2%)
输出内容展示了系统调用main()函前主要进行的工作内容和时间花费,Session上也对每一阶段加载过程具体内容进行了详细的叙述
优化方案
根据上面的描述可得知:
1:在main函数执行前总共用了1.8s
,其中加载动态库用了205.99ms
,指针重定位用了125.12ms
,ObjC类初始化用了572.07ms
,各种初始化耗时976.39ms
.
2:在初始化的过程中,又有已下几个部分的初始化是相对耗时的:libSystem.B.dylib
、libBacktraceRecording.dylib
、 libMainThreadChecker.dylib
、libglInterpose.dylib
、libMTLInterpose.dylib
、vendingMachine
.
main()函数之前耗时的影响因素:
- 动态库加载越多,启动越慢
- ObjC类越多,启动越慢
- C的constructor函数越多,启动越慢
- C++静态对象越多,启动越慢
- ObjC的+load越多,启动越慢
故可以从上面几个方面入手减少pre-main花费的时间:
对动态库加载的时间优化:每个App进行动态库加载中系统级别的动态库占据了绝大数,而针对系统级别的动态库都是经过系统高度优化的,不用担心时间的花费,开发者需尽可能将自身集成的多个动态库合并成单个动态库后再导入,减少动态库集成的数量.
减少Appp的Objective-C类,分类和的唯一Selector的个数:这样做主要是为了加快程序的整个动态链接, 在进行动态库的重定位和绑定(Rebase/binding)过程中减少指针修正的使用,加快程序机器码的生成.
减少Objc运行初始化的时间花费:主要是类的注册,分类的注册,唯一选择器的存在,以及涉及子父类内存布局的Non Fragile ivars偏移的更新,都会影响Objective-C运行时初始化的时间消耗.
尽量不要写attribute((constructor))的C函数,也尽量不要用到C++的静态对象.
ObjC的+load方法能不能最好不用,能用dispatch_once()来完成的,就尽量不要用到以上的方法。
可使用fui (Find Unused Imports)检测未使用到的类.
main()函数之后耗时的影响因素:
- main函数的运行
-
didFinishLaunchingWithOptions
函数的运行
(待完善)
热启动
(待完善)