一般而言,App的启动时间,指的是从用户点击App开始,到用户看到第一个界面之间的时间。总结来说,App的启动主要包括三个阶段:
1.main()函数执行前
;
2.main()函数执行后
;
3.首屏渲染完成后
;
main()函数执行前
在main函数执行前,主要会做以下几件事情:
1.加载可执行文件(App的.o文件的集合)
;
2.加载动态链接库,进行rebase指针调整和bind符号绑定
;
3.Objc运行时的初始化处理,包括objc相关类的注册、category注册、selector唯一性检查等
;
4.初始化,包括了执行+load()方法、attribute((constructor))修饰的函数的调用、创建C++静态全局变量
;
执行先后顺序:+load() -> __attribute__((constructor)) -> main() -> __attribute__((destructor))
此阶段对于启动速度优化来说,可以做的事情包括:
- 减少动态库的加载,在使用较多动态库时,尽量将多个动态库合并,最多可以支持6个非系统动态库合并为一个。
- 减少加载启动后不会去使用的类或者方法。
- +load()方法里的内容放到首屏渲染完成后再执行,或者使用+initialize() 方法替换掉。
- 控制C++全局变量的数量。
main()函数执行后
这一阶段我们通常指的是从main()函数执行开始,到appDelegate的didFinishLaunchingWithOptions方法里首屏渲染相关方法执行完成。优化手段包括:
- 将非首屏渲染需要的功能滞后,放到合适的阶段进行。
- 将首屏渲染前主线程上的耗时方法滞后或者异步执行。
首屏渲染完成后
从函数上来看,这个阶段指的就是截止到didFinishLaunchingWithOptions方法作用域内执行首屏渲染之后的所有方法执行完成。因为用户已经能够看到App的首页信息了,所以优化优先级最低。优化思路:
- 优先处理比较占主线程资源的操作,保证用户后续操作的流畅性。
那么如何对App启动速度进行监控呢?
监控手段主要有两种:
- 定时抓取主线程上的方法调用堆栈,计算一段时间内各个方法的耗时,类似Xcode中的Time Profiler。
- 对objc_msgSend方法进行hook来掌控方法的执行耗时。
hook objc_msgSend方法优点是非常精确,缺点是只能针对oc方法,对于c方法和block,可以使用libffi 的 ffi_call 来达成 hook。
hook objc_msgSend监控工具完整代码见戴铭老师的github:https://github.com/ming1016/GCDFetchFeed/tree/f9d9650b264e720fea14920a3b1a046353a12690/GCDFetchFeed/GCDFetchFeed/Lib/SMLagMonitor
网友评论