今是昨非

今是昨非

日出江花红胜火,春来江水绿如蓝

iOS 启动时间优化

iOS 启动时间优化 —— 相关#

背景#

iOS 的启动时间优化有很多相关的文章,本来不打算写,但是总归是自己整理一遍印象更深刻。这里打算从原理 - 实践 - 面试相关三个方面来入手。首先要理解 APP 启动的原理,启动做了什么?然后针对启动过程中的事件哪些是开发可以进行优化的,去实践?最后则是,面试相关,与启动优化相关的面试有很多,笔者打算列举一下,分别涉及到启动的哪些问题。

启动原理#

启动分为冷启动和热启动。冷启动指的是 APP 进程被杀掉后,从零打开;热启动指的是,APP 进入后台,再切换到前台唤起到过程。这里通常说的启动优化,指的是冷启动优化。(Ps: 这里某些版本会出现,刚杀掉的 APP,立即再次打开,会直接闪退的问题,是系统的 Bug)。

冷启动的过程分为main函数之前(pre-main)main函数之后两个阶段。

pre-main 阶段#

就如很多文章说的:

pre-main 阶段的过程分为dylibs loading ——> rebase/binding ——> ObjC setup ——> initializer四个部分。每个部分吧啦吧啦... 但每次问到这个时候,死记硬背出来真的累人😂。

为什么会感觉困难呢?是因为不知道这四个步骤哪里来的,所以只能背,笔者记忆不好,终归是 “不算年轻了”。
所以除了死记硬背,还能怎么办呢?去实践,然后理解,做过了的事情才印象深刻。

所以来看,如何实践 & 理解:

先打开 Xcode 的 Scheme,然后在 Run 的选项下,选中Environment Variables,添加 Name 为DYLD_PRINT_STATISTICS,Value 为1。如下:

wecom20210803-103910.png

然后运行一次,会发现控制台中打印出了类似如下的信息:


Total pre-main time: 599.52 milliseconds (100.0%)
         dylib loading time: 101.25 milliseconds (16.8%)
        rebase/binding time:  55.26 milliseconds (9.2%)
            ObjC setup time: 189.95 milliseconds (31.6%)
           initializer time: 253.04 milliseconds (42.2%)
           slowest intializers :
             libSystem.B.dylib :   6.65 milliseconds (1.1%)
    libMainThreadChecker.dylib :  59.84 milliseconds (9.9%)
                       xxxTest : 313.12 milliseconds (52.2%)

这里面的信息仔细对比:其中Total pre-main time指的是pre-main的总时间;

Total pre-main timedylib loading time + rebase/binding time + ObjC setup time + initializer time;

slowest intializers中的libMainThreadChecker,是因为 Scheme 中的Main Thread Checker
打开了,关闭即可,如下的地方勾选去除即可。

wecom20210809-101508.png

所以pre-main阶段发生了什么?就是发生了dylib loadingrebase/bindingObjC setup timeinitializer time。这样就知道了这 4 个步骤的来历,接下来再看看这几个步骤都是做什么的?

参考:https://devstreaming-cdn.apple.com/videos/wwdc/2016/406i3zbazbegkeh0udt/406/406_optimizing_app_startup_time.pdf?dl=1

wecom20210809-092908@2x.png

wecom20210809-092815@2x.png

wecom20210809-092553@2x.png

wecom20210809-093129@2x.png

wecom20210809-093951@2x.png

翻译如下:

  • Total pre-main time指的是pre-main的总时间
    • 加载所有依赖的动态库;
    • 修正DATA中的指针偏差;
    • 初始化所有对象。
  • dylib loading time
    • 加载 app 依赖的库
    • 加载库依赖的库
  • rebase/binding time
    • rebasing: 调整镜像的指针
    • binding: 设置指针到外部镜像
  • ObjC setup time
    • 注册 objc 类 (class registration);
    • Category 方法插入;
    • 保证每个 Selector 唯一;
  • initializer time
    • C++ 静态对象初始化
    • objc 的+load方法加载
    • 执行main()

main 函数之后阶段#

main 函数之后的优化,也要多注意,大家都知道application:didFinishLaunchingWithOptions:是启动时初始化的方法,那这里应该做些什么?

首先问大家一个问题

启动优化实践#

application:didFinishLaunchingWithOptions:return YES之前写一个 sleep (10);所以只要这个方法不返回,界面就会显示LaunchScreen,即使已经初始化了首页设置了 rootVC 也不会显示。

面试相关#

+initialize、+init、+load 什么时候调用、调用顺序?

+initialize、+load 的区别?

+load 的加载是在 main 函数之前?还是之后?

参考#

Reducing Your App’s Launch Time
optimizing_app_startup_time
iOS 深思篇 | 启动时间的度量和优化

加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。