深入理解iOS App的启动过程

前言

这里需要清楚两个问题
1、APP的启动步骤
2、如何优化APP的启动速度

APP的启动可以分为2种
冷启动(Cold Launch):从零开始启动APP
热启动(Warm Launch):APP已经在内存中,在后台存活着,再次点击图标启动APP

APP启动时间的优化,主要是针对冷启动进行优化。

如何知道APP冷启动时间:
在Environment Variables中添加DYLD_PRINT_STATISTICS字段,并设置为YES,在控制台就会打印加载时长。

建议启动时间在小于400ms是最佳的,因为从点击图标到显示Launch Screen,到Launch Screen消失这段时间是400ms。

启动步骤

Dyld-Runtime-main三步走

1.当手指点击APP图标时,会创建一个进程
2.然后调用Dyld(动态连接器)接管后续的工作
3.加载可执行文件-dyld会调用 instantiateFromLoadedImage 函数将二级制文件加载到内存 (二进制文件常被称为 image,包括可执行文件、动态库等)
加载过程分三步:
(1)合法性检查,可执行文件是否在当前CPU架构下运行
(2)选在imgaeLoader加载可执行文件。
(3)注册image信息
4.link函数-
(1)首先调用 recursiveLoadLibraries,递归加载程序所需的动态链接库。
(2)Rebase && Bind

  • 因为地址空间加载随机化(ASLR,Address Space Layout Randomization)的缘故,二进制文件最终的加载地址与预期地址之间会存在偏移,所以需要进行 rebase 操作,对那些指向文件内部符号的指针进行修正,在 link 函数中该项操作由 recursiveRebase 函数执行。rebase 完成之后,就会进行 bind 操作,修正那些指向其他二进制文件所包含的符号的指针,由 recursiveBind 函数执行。
    当 rebase 以及 bind 结束时,link 函数就完成了它的使命
    Rebase 修正内部(指向当前mach-o文件)的指针指向
    Bind 修正外部指针指向

5.Dyld 在 bind 操作结束之后,会发出 dyld_image_state_bound 通知,然后与之绑定的回调函数 map_2_images 就会被调用,就是Runtime启动过程(可以看源码)
它主要做以下几件事来完成 Objc Setup: 简称初始化Objective C Runtime
1、调用map_images进行读取可执行文件的 DATA 段内容,找到与 objc 相关的信息
2、注册 Objc 类一个TableVIew里面
3、Category中的方法注册到对应的类中
4、确保 selector 的唯一性
到此为止,可执行文件和动态库中所有的符号(Class,Protocol,Selector,IMP,…)都已经按格式成功加载到内存中,被runtime 所管理成功加载到内存中,被runtime 所管理。

6.Initializers
Objc SetUp 结束后,Dyld 便开始运行程序的初始化函数,该任务由 initializeMainExecutable 函数执行。整个初始化过程是一个递归的过程,顺序是先将依赖的动态库初始化,然后在对自己初始化。初始化需要做的事情包括:
1. 调用 Objc 类的 + load 函数
2. 调用 C++ 中带有 constructor 标记的函数
3. 非基本类型的 C++ 静态全局变量的创建
main
当初始化结束之后,可执行文件才处于可用状态,之后 Dyld 就会去调用可执行文件的 main 函数,开始程序的运行。

启动时间优化

iOS启动优化:
启动时间的优化实际上可以分为两个阶段,pre-main阶段的优化和进入didFinish方法到进入主界面时间。

  1. pre-main阶段的优化
  • 删除无用的系统库,第三方SDK
  • 删除无用类(.h.m等)文件
  • 梳理各个类的+load方法,将多个类中+load方法可以做的事延迟到+initiailize里去做。
  1. main()阶段的优化
  • 梳理出来didFinishLaunchingWithOptions方法到第一个主界面导致延迟加载的原因并改进。例如网络数据的加载,界面的加载,第三方SDK的初始化,新版本检查等等。

你可能感兴趣的:(深入理解iOS App的启动过程)