iOS startup optimization

Application startup optimization

When we participate in large-scale applications, we will encounter some situations where the startup time is too long. At this time, we need to use related operations.
In summary, before the main() method is called, the startup process is roughly divided into the following steps:
First, LLVM translates the project into an IR file and then to backend a>

  1. LLVM clang

  2. pre-main

  3. main

  4. binding – symbol binding

  5. rebase - pointer repair (iOS14.3 introduces ASLR 'address space randomization' to solve the problem of virtual memory starting from 0, physical memory address is random - not enough memory' by writing to physical memory, and then reading from physical memory when used ' )

  6. MMU memory management unit – translation address – page (page)

    1. The kernel loads the executable file

    2. load dylibs image (dynamic library image file required for loading the program)

    3. Rebase image / Bind image (Due to the existence of ASLR (address space layout randomization), the loading addresses of executable files and dynamic link libraries in virtual memory are not fixed every time they are started, so the resource pointers in the image need to be repaired)

    4. Objc setup (register the Objc class and insert the methods in the Category into the method list)

    5. initializers (call the +load() method of the Objc class, call the constructor of the C++ class)

·It is still necessary to optimize the APP startup time.

   关于APP启动时间的分析和优化可以以main()为分界点,分为main()方法执行之前的加载时间(pre-main time)和main()之后的加载时间。那么,如何定量的测量这两个阶段具体的执行时间呢,下面先给出测量方法,看一下自己项目启动时间是否合理:

Just add the environment variable parameter DYLD_PRINT_STATISTICS in Xcode, so that the time spent in pre-main will be printed on the console when running the APP
If you want to print detailed pre-main For the time spent in each process, you can add another DYLD_PRINT_STATISTICS_DETAILS parameter. The values ​​of pre-main time and total time are different. In fact, the total time - debugger pause time below is larger than the pre-main time above
(PS: Because these two attributes are invalid after iOS13, you need to use a simulator below iOS13 when using them)

If you want to print the order in which dyld loads dynamic libraries, you can set the environment variable DYLD_PRINT_LIBRARIES.
Picture:
Insert image description here
Insert image description here

Please add image description

Analysis of the startup process before main() method call:

After the App starts, the system kernel (XNU) first loads the executable file (a collection of all .o files of its own App), and then loads the dynamic linker dyld. dyld is a library specially used to load dynamic link libraries. Execution starts with dyld, which starts with the dependencies of the executable file and recursively loads all dependent dynamic link libraries.

(Supplement: After the user clicks the icon, a system call execve will be sent to the kernel, and the kernel will create a process. Then the main binary will be mmapped in, read LC_LOAD_DYLINKER in the load command, and find the path of dyld. Then mmap dyld to the virtual memory. Find dyld's entry function _dyld_start (eventually transferred to dyld's _main function), set the PC register to _dyld_start, and then hand over the startup process to dyld.)

Dynamic link libraries include: all system frameworks used in iOS, libobjc that loads OC runtime methods, and system-level libSystem, such as libdispatch (GCD) and libsystem_blocks (Block).

Optimize actions

1. Reduce the references to dynamic libraries, delete unused Frameworks in the project in time, and no longer reference system libraries that are not used in General -> Linked Frameworks and Libraries in the Xcode configuration.

2. Merge dynamic libraries.

3. Try not to use embedded dylib. Loading embedded dylib has a large performance overhead.

4. Clean up redundant classes and categories in the project. If the same class has multiple categories, it is recommended to merge them.

5. Delay things that do not have to be done in the +load method to +initialize.

6. Try not to use C++ virtual functions (there is overhead in creating a virtual function table), and do not do a lot of time-consuming operations in the C++ constructor.

Find classes not used in the project

Download tool fui, link: https://github.com/dblock/fui

After downloading and installing the tool
cd to the project directory and run $fui find, and then the unused classes will be printed out

How to find functions that have not been called

python FindSelectorsUnrefs.py -a {
    
    这里是工程中.app文件的地址在finder找到直接拖过来}

The corresponding script FindSelectorsUnrefs.py can be found in the resources I uploaded.

Find image resources that are not used in the project

Find LSUnusedResources in the resource file I uploaded, run the Mac application and drag the project into it.

binary rearrangement

Insert image description here

By creating an .order file and binding it to the project, when the APP is started, the symbols we need can be ranked first according to the content we have formulated, reducing the number of page faults during the startup process of our program, thereby reducing the startup time. As for how to know the correct training to optimize?

clang instrumentation

Method:
By overriding the method in the viewcontroller page and printing out __fun__

void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
    
    

        if (!*guard) return;
            //可以根据函数找到对应符号的名称和地址。
    void *PC = __builtin_return_address(0);
    Dl_info info;
    dladdr(PC, &info);
    NSLog(@"\n dli_sname=%s",info.dli_sname);
}

The system will first return the number of compiled files in __sanitizer_cov_trace_pc_guard_init. Each time the method is called, it will go through the callback method of __sanitizer_cov_trace_pc_guard. The binary rearrangement can be done by using the order printed here and then specifying the loading order in .order. The methods of the classes that need to be called are loaded first, thereby improving the startup speed of the APP.

So how can the system execute the above method before each method messagesend?
Insert image description here
As shown in the figure, first go to the buildSetting configuration

Guess you like

Origin blog.csdn.net/lingjunjie/article/details/128386577