今是昨非

今是昨非

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

iOS startup time optimization

Background#

There are many articles related to iOS startup time optimization, and I didn't plan to write one myself. However, I decided to organize my thoughts on this topic to deepen my understanding. In this article, I will approach it from three aspects: principles, practice, and interview-related topics. First, it is important to understand the principles behind app startup and what happens during the startup process. Then, we can identify the events during startup that developers can optimize and put them into practice. Finally, I will discuss interview questions related to startup optimization and the issues they cover.

Startup Principles#

Startup can be divided into cold startup and warm startup. Cold startup refers to opening the app from scratch after the app process has been terminated, while warm startup refers to the process of bringing the app to the foreground after it has been in the background. When we talk about startup optimization, we usually refer to cold startup optimization. (Note: In some versions, there is a bug where the app crashes immediately when reopened after being terminated. This is a system bug.)

The cold startup process can be divided into 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, and initializer. Each part has its own details... But it can be tiring to memorize them every time you are asked about it. 😂

Why does it feel difficult? It's because we don't know where these four steps come from, so we can only memorize them. I have a poor memory, so I'm definitely "not that young anymore".

So, besides memorizing, what else can we do? We can put it into practice, understand it, and make a deeper impression by actually doing it.

So let's see how to put it into practice and understand it:

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

wecom20210803-103910.png

Then run the app 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%)

Let's compare the information in it carefully:

  • Total pre-main time refers to the total time of the pre-main stage.
  • Total pre-main timedylib loading time + rebase/binding time + ObjC setup time + initializer time.
  • In the slowest intializers section, libMainThreadChecker is there because the Main Thread Checker is enabled in the Scheme. You can disable it by unchecking the option below:

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 take a look at what each of these steps does.

Reference: Optimizing App Startup Time

wecom20210809-092908@2x.png

wecom20210809-092815@2x.png

wecom20210809-092553@2x.png

wecom20210809-093129@2x.png

wecom20210809-093951@2x.png

Translation:

  • Total pre-main time refers to the total time of the pre-main stage.
    • 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 +load methods.
    • Executing main().

Post-main Stage#

Optimization after the main function is also important. We all know that application:didFinishLaunchingWithOptions: is the method for initializing the app during startup. So what should we do here?

Let me ask you a question first:

Startup Optimization Practice#

In application:didFinishLaunchingWithOptions:, add sleep(10) before return YES. As long as this method does not return, the LaunchScreen will be displayed, even if the home screen has been initialized and the root view controller has been set, it will not be displayed.

When are +initialize, +init, and +load called? What is the order of their execution?

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 Startup Time

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