iOS 端启动速度优化
应用启动流程
iOS 启动可以分为pre-main阶段和main()阶段
pre-main阶段
- 加载可执行文件
- 加载动态链接库加载器
dyld - 递归加载动态链接库
dylib
main 阶段
dyld调用main- 调用
UIApplicationMain - 调用
applicationWillFinishLaunching - 调用
didFinishLaunchingWithOptions
耗时测量
pre-main 阶段
Xcode的环境变量中DYLD_PRINT_STATICTICS= 1- 日志里面会有详细的内容
main 阶段
- 测量
main->didFinishLaunchingWithOptions的时间
优化思路
dyld加载步骤Load dylibs分析依赖、
Mach-o文件、验证有效性、代码签名注册到内核、对dylib的segment调用mmap- 避免使用
embedded dylib - 合并已有的
dylib, 使用静态库 - 懒加载
dylib
- 避免使用
Rebase/BindRebase读入镜像、修正ASLR导致的内存地址的偏差。消耗在文件I/O。Bind查询符号表、设置镜像的外部指针。消耗在CPU计算- 减少
ObjC的Class、Selector、Category数量 - 减少
C++虚函数数量(创建虚函数表有开销) - 使用
Swift struct(内部做了优化、符号开销少)
- 减少
Object setupdyld会注册声明过的ObjC类,将分类方法插入到类的方法列表中、检查selector的唯一性Initializersdyld开始运行程序的初始化函数、调用每个ObjC类和分类的+load方法,调用C/C++中的构造器函数 (__attibute__(constructor)修饰的函数), 创建非基本类型的C++静态全局变量,随后调用main函数- 减少
+load函数做的事情,推迟到+initialize中 - 减少构造器函数的个数,在构造器函数里少作些事情
- 减少
C++静态全局变量个数
- 减少
main 阶段
减少
didFinishLaunchingWithOptions方法里的事情
- 梳理依赖库、延迟加载可以延迟加载的库
- 把可以延迟执行的逻辑,放到后面。
- 避免复杂/多余计算
- 避免在 viewDidLoad 和 viewWillAppear中做太多的事情
- 首页控制器用纯代码方式构建