资料梳理-App启动流程

本文详细介绍了App启动过程中Dyld2的加载流程,包括加载dyld到App进程、加载动态库、Rebase/Bind操作、初始化ObjectiveC Runtime及其它初始化代码。并对比了Dyld3的部分out-of-process特性,以及如何使用环境变量查看App启动时间。
摘要由CSDN通过智能技术生成

App启动Dyld2流程:

  1. 加载dyld到App进程
  2. 加载动态库(包括所依赖的所有动态库)
  3. Rebase/Bind
  4. 初始化Objective C Runtime
  5. 其它的初始化代码

1.加载dyld到App进程 

    系统加载程序可执行文件Mach-O(Header,LoadCommands,Data)后,通过分析文件LoadCommands->LC_LOAD_DYLINKER来获得dyld所在路径/usr/lib/dyld 来加载dyld,然后就将后面的事情甩给dyld了。

2.加载动态库(包括所依赖的所有动态库)

    dyld会首先读取mach-o文件的Header和load commands。接着就知道了这个可执行文件依赖的动态库。例如加载动态库A到内存,接着检查A所依赖的动态库,就这样的递归加载,直到所有的动态库加载完毕。通常一个App所依赖的动态库在100-400个左右,其中大多数都是系统的动态库,它们会被缓存到dyld shared cache,这样读取的效率会很高。

3.Rebase/Bind

    ASLR的全称是Address space layout randomization,翻译过来就是“地址空间布局随机化”。App被启动的时候,程序会被影射到逻辑的地址空间,这个逻辑的地址空间有一个起始地址,而ASLR技术使得这个起始地址是随机的。如果是固定的,那么黑客很容易就可以由起始地址+偏移量找到函数的地址。

    Code Sign相信大多数开发者都知晓,这里要提一点的是,在进行Code sign的时候,加密哈希不是针对于整个文件,而是针对于每一个Page的。这就保证了在dyld进行加载的时候,可以对每一个page进行独立的验证。

    Rebase 修正内部(指向当前mach-o文件)的指针指向,Rebase解决了内部的符号引用问题,而外部的符号引用则是由Bind解决。在解决Bind的时候,是根据字符串匹配的方式查找符号表,所以这个过程相对于Rebase来说是略慢的。

    Bind 修正外部指针指向,之所以需要Rebase,是因为刚刚提到的ASLR使得地址随机化,导致起始地址不固定,另外由于Code Sign,导致不能直接修改Image。Rebase的时候只需要增加对应的偏移量即可。待Rebase的数据都存放在__LINKEDIT中。

4.初始化Objective C Runtime

    Objective C是动态语言,所以在执行main函数之前,需要把类的信息注册到一个全局的Table中。同时,Objective C支持Category,在初始化的时候,也会把Category中的方法注册到对应的类中,同时会唯一Selector,这也是为什么当你的Cagegory实现了类中同名的方法后,类中的方法会被覆盖。

    另外,由于iOS开发时基于Cocoa Touch的,所以绝大多数的类起始都是系统类,所以大多数的Runtime初始化起始在Rebase和Bind中已经完成。

5.其它的初始化代码

    接下来就是必要的初始化部分了,主要包括几部分:1. +load方法  2. C/C++静态初始化对象和标记为attribute(constructor)的方法。这里要提一点的就是,+load方法已经被弃用了,如果你用Swift开发,你会发现根本无法去写这样一个方法,官方的建议是实用initialize。区别就是,load是在类装载的时候执行,而initialize是在类第一次收到message前调用。

备注:

以上是dyld2加载流程

dyld3则是部分out-of-process,部分in-process。在App下载安装和版本更新的时候会去执行,out-of-process会做如下事情:

  • 分析Mach-o Headers
  • 分析依赖的动态库
  • 查找需要Rebase & Bind之类的符号
  • 把上述结果写入缓存

这样,在应用启动的时候,就可以直接从缓存中读取数据,加快加载速度。

    在Xcode中,可以通过设置环境变量来查看App的启动时间,DYLD_PRINT_STATISTICS和DYLD_PRINT_STATISTICS_DETAILS。

Edit Scheme->Run->Arguments->Environment Variables->DYLD_PRINT_STATISTICS:1

Total pre-main time: 654.59 milliseconds (100.0%)
         dylib loading time: 119.99 milliseconds (18.3%)
        rebase/binding time: 380.23 milliseconds (58.0%)
            ObjC setup time:  68.40 milliseconds (10.4%)
           initializer time:  85.82 milliseconds (13.1%)
           slowest intializers :
             libSystem.B.dylib :   3.07 milliseconds (0.4%)
    libMainThreadChecker.dylib :  14.79 milliseconds (2.2%)
                  LoveOfPomelo : 120.48 milliseconds (18.4%)

Edit Scheme->Run->Arguments->Environment Variables->DYLD_PRINT_STATISTICS_DETAILS:1

  total time: 924.43 milliseconds (100.0%)
  total images loaded:  305 (0 from dyld shared cache)
  total segments mapped: 908, into 125240 pages with 9067 pages pre-fetched
  total images loading time: 650.11 milliseconds (70.3%)
  total load time in ObjC:  75.70 milliseconds (8.1%)
  total debugger pause time: 462.64 milliseconds (50.0%)
  total dtrace DOF registration time:   0.14 milliseconds (0.0%)
  total rebase fixups:  3,212,220
  total rebase fixups time:  43.73 milliseconds (4.7%)
  total binding fixups: 366,847
  total binding fixups time:  47.16 milliseconds (5.1%)
  total weak binding fixups time:   1.59 milliseconds (0.1%)
  total redo shared cached bindings time:  47.97 milliseconds (5.1%)
  total bindings lazily fixed up: 0 of 0
  total time in initializers and ObjC +load: 105.96 milliseconds (11.4%)
                         libSystem.B.dylib :  42.99 milliseconds (4.6%)
               libBacktraceRecording.dylib :   3.14 milliseconds (0.3%)
                            CoreFoundation :   1.51 milliseconds (0.1%)
                                Foundation :   1.83 milliseconds (0.1%)
                libMainThreadChecker.dylib :  15.29 milliseconds (1.6%)
                              LoveOfPomelo :  78.05 milliseconds (8.4%)
total symbol trie searches:    177022
total symbol table binary searches:    0
total images defining weak symbols:  31
total images using weak symbols:  82

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值