iOS启动流程

作者: 临川慕容吹雪 | 来源:发表于2019-03-22 19:03 被阅读0次

    关于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工具打开了我本地的一个动态库。如图:

    mach-o.jpg

    关于 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加载各种运行参数和环境变量。

    • 加载共享缓存

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

    • 加载可执行文件

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

    • 加载动态库

      会先从共享缓存中搜索

    • 链接主程序,进行 rebase 指针调整

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

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

    • 运行时Runtime 初始化

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



      我们可以看到:
      栈底的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()函数之后:

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

    参考:

    iOS 程序 main 函数之前发生了什么

    App启动流程

    iOS程序启动->dyld加载->runtime初始化(初识)

    dyld详解

    戴铭大神的 App 启动速度怎么做优化与监控

    相关文章

      网友评论

        本文标题:iOS启动流程

        本文链接:https://www.haomeiwen.com/subject/gmnrvqtx.html