1、整体过程
(1)解析Info.plist
(2)Mach-O(可执行文件)加载
(3)程序执行
2、阶段:
分为两个阶段,pre-main阶段和main()阶段。程序启动到main函数执行前是pre-main阶段;在执行main函数后,调用AppDelegate中的-application:didFinishLaunchingWithOptions:方法完成初始化,并展示首页,这是main()阶段,或者叫做main()之后阶段。
rebase指针调整和bind符号绑定。ObjC的runtime初始化(ObjC setup):ObjC相关Class的注册、category注册、selector唯一性检查等。+load()方法、用attribute((constructor))修饰的函数的调用、创建C++静态全局变量等。1、pre-main阶段
对于pre-main阶段,Apple提供了一种测量方法,在 Xcode 中 Edit scheme -> Run -> Auguments 将环境变量DYLD_PRINT_STATISTICS 设为1 。之后控制台会输出类似内容,我们可以清晰的看到每个耗时:

从上面可以看出时间区域主要分为下面几个部分:
ASLR(Address Space Layout Randomization),地址空间布局随机化。在ASLR技术出现之前,程序都是在固定的地址加载的,这样hacker可以知道程序里面某个函数的具体地址,植入某些恶意代码,修改函数的地址等,带来了很多的危险性。ASLR就是为了解决这个的,程序每次启动后地址都会随机变化,这样程序里所有的代码地址都需要需要重新对进行计算修复才能正常访问。rebasing这一步主要就是调整镜像内部指针的指向。
Binding:将指针指向镜像外部的内容。
objc_init方法,这个是runtime的初始化方法,在这个方法里面主要的操作就是加载类(对需要的class和category进行注册);load_images方法,这个方法里面就是加载对应image里面的类,并调用load方法(在下一阶段initializer)。load方法,然后调用子类的,但是在load里面不能调用[super load]。最后才是调用category的load方法。总之,所有的load都会被调用到(注意:子类的initialize方法会覆盖父类,不同于load方法)。承接上一过程进行初始化(load)。如果我们代码里面使用了clang的__attribute__((constructor))构造方法,这里会调用到。
2、main()阶段
测量main()函数开始执行到didFinishLaunchingWithOptions执行结束的时间,简单的方法:直接插入代码。(也可以使用其他工具)

![]()
![]()
三、改善APP的启动
建议应用的启动时间控制在400ms之下,并且在20s内启动,否则系统会kill app。优化APP的启动时间,需要就是分别优化pre-main和main的时间。
1、改善启动时pre-main阶段
(1)加载 Dylib
大部分ObjC初始化工作已经在Rebase/Bind阶段做完了,这一步dyld会注册所有声明过的ObjC类,将分类插入到类的方法列表里,再检查每个selector的唯一性。
在这一步倒没什么优化可做的,Rebase/Bind阶段优化好了,这一步的耗时也会减少。
(4)Initializers
到了这一阶段,dyld开始运行程序的初始化函数,调用每个Objc类和分类的+load方法,调用C/C++ 中的构造器函数(用attribute((constructor))修饰的函数),和创建非基本类型的C++静态全局变量。Initializers阶段执行完后,dyld开始调用main()函数。
在这一步,我们可以做的优化有:
(1)核心点:didFinishLaunchingWithOptions方法
这一阶段的优化主要是减少didFinishLaunchingWithOptions方法里的工作,在didFinishLaunchingWithOptions方法里我们经常会进行:
由于历史原因,这里的代码容易变得比较庞大,启动耗时难以控制。
(2)优化点:
满足业务需要的前提下,didFinishLaunchingWithOptions在主线程里做的事情越少越好。在这一步,我们可以做的优化有:
原文:https://www.cnblogs.com/cleven/p/12796608.html