今是昨非

今是昨非

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

iOS Launch Time Optimization

Background#

There are many articles related to optimizing the launch time of iOS apps. I didn't plan to write one myself, but I thought it would be more memorable if I organized my own impressions. Here, I plan to start from the aspects of principles, practice, and interview-related topics. First, we need to understand the principles of app launch and what happens during the launch. Then, we can explore the events during the launch process that developers can optimize and put them into practice. Finally, I will list some interview questions related to launch optimization, covering various aspects of the launch process.

Launch Principles#

Launch can be divided into cold launch and warm launch. Cold launch refers to opening the app from scratch after the app process has been terminated, while warm launch refers to bringing the app to the foreground from the background. When people talk about launch optimization, they usually refer to cold launch optimization. (Ps: In some versions, there is a bug where if you immediately reopen a just-terminated app, it will crash).

The cold launch process consists of two stages: pre-main and post-main.

Pre-main Stage#

As many articles have mentioned:

The pre-main stage consists of four parts: dylibs loading -> rebase/binding -> ObjC setup -> initializer. Each part has its own details... But every time I'm asked about this, it's really tiring to recite it from memory 😂.

Why does it feel difficult? It's because I don't know where these four steps come from, so I can only memorize them. I have a bad memory, after all, "I'm not young anymore".
So besides memorizing, what else can I do? Practice, and then understand. Things that have been done leave a deeper impression.

So let's see how to practice and understand:

First, open Xcode's Scheme, then under the Run options, select Environment Variables and add Name as DYLD_PRINT_STATISTICS and Value as 1. Like this:

wecom20210803-103910.png

Then run it once, and you will see similar information printed in the console:


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%)

Carefully compare the information in it: Total pre-main time refers to the total time of pre-main;

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

In slowest intializers, libMainThreadChecker is because the Main Thread Checker in the Scheme is turned on. You can turn it off by unchecking the following option.

wecom20210809-101508.png

So what happens in the pre-main stage? It goes through dylib loading, rebase/binding, ObjC setup time, and initializer time. Now we know where these four steps come from. Next, let's see what each of these steps does.

Reference: 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

Translated as follows:

  • Total pre-main time refers to the total time of pre-main
    • Loading all dependent dynamic libraries
    • Adjusting pointer offsets in DATA
    • Initializing all objects
  • dylib loading time:
    • Loading libraries that the app depends on
    • Loading libraries that the libraries depend on
  • rebase/binding time:
    • Rebasing: Adjusting pointers in the image
    • Binding: Setting pointers to external images
  • ObjC setup time:
    • Registering objc classes (class registration)
    • Inserting Category methods
    • Ensuring each Selector is unique
  • initializer time:
    • Initializing C++ static objects
    • Loading objc's +load methods
    • Executing main()

Post-main Stage#

Optimizing after the main function is also important. Everyone knows that application:didFinishLaunchingWithOptions: is the method for initialization during launch. So what should be done here?

Let me ask you a question first.

Launch Optimization Practice#

Add sleep(10) before return YES in application:didFinishLaunchingWithOptions:. As long as this method doesn't return, the LaunchScreen will be displayed, even if the home page has been initialized and the rootVC has been set, it won't be shown.

When are +initialize, +init, and +load called? What is the calling order?

What is the difference between +initialize and +load?

Is +load loaded before or after the main function?

References#

Reducing Your App’s Launch Time
optimizing_app_startup_time
iOS Deep Thoughts | Measurement and Optimization of Launch Time

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.