iOS程序启动过程及优化方案

timg.png

一、准备知识

1. App打开时间

t = t1 + t2;
t1 = 系统dyld和自身App的加载时间
t2 = main函数运行到AppDelegate的

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(nullable NSDictionary *)launchOptions NS_AVAILABLE_IOS(3_0);

方法执行。

2. Mach-O 应用的主要二进制文件

包含:
(1) _TEXT : Mach Header 包含被执行的代码和只读数据.
(2) _DATA : 包含全库变量,静态变量,可读写。
(3) _LINKEDIT : 包含加载程序的元数据,比如函数的名称和地址。

3. dyld 动态链接器

程序启动运行时会依赖很多系统动态库,而系统动态库会通过dyld(动态加载器)(/usr/lib/dyld)加载到内存中,最开始系统内核读取程序可执行文件的Header段信息做一些准备工作,之后就会将工作交给dyld。由于不止一个程序需要使用系统动态库,所以不可能在每个程序加载时都去加载所有的系统动态库,为了优化程序启动速度和利用动态库缓存,苹果从iOS3.1之后,将所有系统库(私有与公有)编译成一个大的缓存文件,这就是dyld_shared_cache,该缓存文件存在iOS系统下的/System/Library/Caches/com.apple.dyld/目录下

Bundle不能被链接,只能在运行时使用dlopen()加载

二、启动过程

main()函数前:

  • 系统读取App的可执行文件(Mach-O文件),从中获取dyld的路径。
  • 加载dyld去初始化运行环境,开启缓存策略,加载程序相关的依赖库(其中包括可执行文件),并对这些库进行链接。
  • 调用每个依赖库的初始化方法,在这一步,runtime被初始化。
  • 所有依赖库初始化后,可执行文件进行初始化。
  • runtime对项目中所有的类进行结构初始化,调用load方法。
  • dyld返回main函数地址,main函数调用,进入程序入口。
load.png

main()函数:

  • main()函数调用
  • UIApplicationMain()函数调用
  • UIApplicationMain函数内部:
    * 创建UIApplication对象,是应用对象的象征。
    * 再创建一个UIApplication的delegate对象,负责监听UIApplication的生命周期。
    * 当UIApplication的生命周期发生变化的时候,会给delegate对象发送不同的消息。
    * 开启Runloop保持程序一直运行。
    * 加载info.plist和启动图片,判断有没有Main.storyboard.

三、优化启动时间

(1)内嵌的dylib尽可能少,或者合并起来。
(2)Rebase/Binding减少_DATA中需要修正的指针,对于OC来说减少class、selctor、category这些元数据的数据量;对于c++来说减少虚函数数量。
(3)将不必须在load()中做的推迟到initialize中。
(4)不使用xib,直接用代码加载视图。
(5)release不要使用NSLog输出。
(6)启动时网络请求尽可能使用异步。

四、附带dylib加载过程

dyllib加载过程.png

你可能感兴趣的:(iOS程序启动过程及优化方案)