635,iOS启动流程(面试点:App启动主要包括三个阶段:减少动态库数量,可以合并动态库 减少无用的方法和类,合并分类 减少 在load方法,试着用Initialize替代 减少atri...

关于mach-o
mach-O文件为Mach Object文件格式的缩写,它是一种用于可执行文件,目标代码,动态库,内核转储的文件格式。
常见的有以下形式:

  • Executable 可执行文件
  • Dylib动态库和Framework动态库,对应头文件和资源文件集合

Apple可执行文件格式几乎都是mach-o;

关于更多mach-o ,可参考Mac OS X ABI Mach-O File Format Reference

关于mach-o数据结构,可参考Mac本地路径下的/usr/include/mach-o源码。

为了直观看出mach-o相关信息,可以使用三方工具MachOView

MachOView下载

编译好的工程很老了,建议下载源码自己运行使用。

MachOView源码地址

关于安装源码启动报错,可参看别人已经写好的说明,我这边就不多说了。

mach-o文件分析工具 MachOview探究

这里我用MachOView工具打开了我本地的一个动态库。如图:

image.png

关于 dyld

dyld(the dynamic link editor)是苹果的动态链接器,在系统内核做好程序准备工作之后,交由dyld负责余下的工作。它代码是开源的。源码地址。
在App启动时它就负责加载mach-o文件。
关于 dyld详细解析说明,可参考dyld详解

App 具体启动流程

App启动一般分两种冷启动和热启动:

  • 冷启动是指, App 点击启动前,它的进程不在系统里,需要系统新创建一个进程分配给它启动的情况。这是一次完整的启动过程。

  • 热启动是指 ,App 在冷启动后用户将 App 退后台,在App 的进程还在系统缓存的情况下,用户重新启动进入 App。

这里我们说的主要是冷启动。

App启动主要包括三个阶段:

1: main()函数执行前

这里就主要是dyld加载mach-o文件了

加载步骤主要分以下几步:

  • 设置运行环境

主要设置运行参数,环境变量之类的。可以再xcode的 Product->Scheme -> EditScheme,配置环境变量DYLD_PRINT_OPTSDYLD_PRINT_ENV,通过xcode打印dyld加载各种运行参数和环境变量。

image.png
  • 加载共享缓存

如果共享缓存已加载就不在额外处理。

  • 加载可执行文件

  • 主程序的Mach-O加载进内存,并实例化一个ImageLoader
    ImageLoader是抽象类,其子类负责把Mach-O文件实例化。

  • 加载动态库

    会先从共享缓存中搜索

  • 链接主程序,进行 rebase 指针调整
    将实例化后的主程序进行动态修正,让二进制变为可正常执行的状态。
    Rebase 修正内部(指向当前mach-o文件)的指针指向.

  • Bind 修正外部指针指向
    包括链接插入的动态库,执行弱符号绑定。

  • 运行时Runtime 初始化
    相关类注册分类注册,方法唯一性检查.
    我们可以通过先加符号断点 断在_objc_init,就可清晰看到dyld执行到runtime初始化
    之前的调用了。

image.png
image.png

我们可以看到:
栈底的dyldbootstrap::start()方法,继而调用了dyld::_main()方法,再到ImageLoader,再到objc_init

  • 其他必要的初始化

  • +load方法,

  • C/C++静态初始化对象和标记为attribute(constructor)的方法

2:main()函数执行后

从main()函数执行开始,到appDelegate 的 didFinishLaunchion里首屏渲染相关方法执行完成。

3:首屏渲染完成之后

其他业务模块相关代码初始化,文件处理,业务监听等等。

App启动时间优化

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

通过了解App启动流程,我们可以做以下优化

main()函数执行前:

  • 减少动态库数量,可以合并动态库

  • 减少无用的方法和类,合并分类

  • 减少 在load方法,试着用Initialize替代

  • 减少atribute((constructor))的使用,控制全局变量数量

main()函数之后:

对业务进行模块化处理,非首屏渲染业务应当尽量放到首屏渲染之后处理。

你可能感兴趣的:(635,iOS启动流程(面试点:App启动主要包括三个阶段:减少动态库数量,可以合并动态库 减少无用的方法和类,合并分类 减少 在load方法,试着用Initialize替代 减少atri...)