preface
As programmers, “performance optimization” is a term we’re all familiar with, and something we need to work on constantly and continuously; In fact, optimization is a very big topic, because there are more than ten kinds of optimization directions, but do not blindly optimize in the actual development process, which may sometimes cause the opposite of the negative effect, we need to optimize according to the actual scene and business needs. Next, the thesis will discuss the startup optimization of iOS App.
Start the process
As we all know, the startup of iOS App is divided into pre-main and main() stages, and in these two stages, the system will carry out a series of loading operations, the process is as follows:
1 , pre-main phase
1. Load the executable file of the application
2. Load the DYLD dynamic connector
3. Dyld recursively loads dylib, the dynamic link library that all applications depend on
2 , main() phase
1. dyld calls main()
2. Calls UIApplicationMain ()
3. Call applicationWillFinishLaunching
4. Call didFinishLaunchingWithOptions
Stage optimization term
1 , pre-main phase
When Optimizing for the pre-main stage, we need to understand the loading process in detail, which can be detailed in WWDC 2016 Optimizing Time App Startup Time
1.1 Load dylibs
At this stage dyLD analyzes the dylib (changed to.tbd after Xcode7) on which the application depends, finds its Mach-o files, opens and reads these files and verifies their validity, then finds the code signature to register with the kernel, and finally calls mmap() on each segment of dylib. However, dylib here is mostly a system library and does not require additional optimization.
Optimization conclusions:
1. Try not to use embedded dylib to avoid increasing Load dylibs overhead
2. Merge existing dylib and use static archives to reduce the number of dylib uses
Lazy loading dylib, but be aware that dlopen() can cause some problems and actually does more work
1.2 Rebase/Bind
In the process of loading dylib, the system introduced ASLR (Address Space Layout Randomization) technology and code signature for safety. Due to ASLR, images (including executables, dylib, and bundle) are loaded at random addresses, and there is a slide deviation from the preferred_address, which dyLD needs to fix to point to the correct address. Rebase comes first, and Bind comes second. Rebase reads the image into memory and corrects the pointer inside the image. What Bind does is query the symbol table and set Pointers to the outside of the image, and the performance cost is mostly CPU.
Optimization conclusion: In this process, we need to pay attention to minimize the number of Pointers, such as:
-
Reduce the number of ObjC classes, methods, and categories
-
Reduce the number of C++ virtual functions (creating virtual tables is expensive)
3. Use Swift struct (internally optimized, with fewer symbols)
1.3 Objc setup
Most of the ObjC initialization is done in the Rebase/Bind phase, where DyLD registers all declared ObjC classes, inserts classes into the class’s list of methods, and checks for the uniqueness of each selector.
There isn’t much optimization to do at this stage, and once you’ve optimized the Rebase/Bind phase, this step takes less time.
1.4 Initializers
At this stage, DyLD starts running the program’s initialization functions, calling the +load method for each Objc class and class, calling the C/C++ constructor functions (functions modified with attribute(((constructor))), and creating C++ static global variables of non-primitive types. After the Initializers phase is complete, Dyld starts calling main().
Optimization conclusions:
-
Do fewer things in the class’s +load method and try to defer those things to +initiailize
-
Reduce the number of constructor functions and do fewer things in constructor functions
-
Reduce the number of constructor functions and do fewer things in constructor functions
2 , main() phase
Main optimization in this stage, the emphasis on the SDK initialization tool, business registration, whole didFinishLaunchingWithOptions method, because some of our third party app style configuration, start guide page displays a status logic, version update logic and so on are the basic party here, If this logic is not optimized, the startup time will be prolonged as the service expands.
Optimization conclusions:
On the premise of meet the needs of the business, as far as possible ways to reduce didFinishLaunchingWithOptions event processing logic in the main thread, such as:
-
According to the actual business situation, comb each two-party/three-party library, find the library that can be lazy loading, and do lazy loading processing, for example, put it into the viewDidAppear method of the home controller.
-
Sort out the business logic and delay the execution of the logic that can be delayed. Check for new versions, register for push notifications, and so on
-
Avoid complex/redundant computational logic, which should be deferred asynchronously
-
Avoid doing too much blocking on the main thread of the home controller’s viewDidLoad and viewWillAppear methods until they are done
Scene added
In addition, in our actual development process, the home page controller of many projects will have some background configurable, relatively rich structure or recommended data to display, and our home page display speed is usually included in the start of optimization, in fact, for this type of optimization, If we just use the traditional API -> data -> UI method, it is difficult to have a significant improvement space, because the user’s network state is not controllable, if we do not do other processing, then in many scenarios for users, even if we put some placeholder map, the display style is very unfriendly. After all, the first visual impact of the home controller on the user is relatively large.
For optimization in this scenario, we can generally adopt the method of Local + Network + Update to optimize the loading speed of the home page to a certain extent:
1. In the process of APP update, first of all, local embedded processing logic, embedded home page data structure (localDataBase), embedded home page style required resources (localStorage)
2. After the installation and startup, compare the local and online data update records to detect whether the local embedded data structure needs to be updated
3. When the data that needs to be updated is detected, the specified structure will be updated silently and the local data structure will be updated synchronously
The benefits of this are:
1. The home page data is directly loaded from the local PC to reduce the waiting time of network data
2. Only detect the change of data key value, and compare the directional update structure with small data volume to reduce API data exchange frequency and packet volume
3, to ensure that the home page for users will always be in a friendly display state
Of course, this is not the only way to deal with it, and it is not suitable for all scenarios. It only provides a way of thinking, and it is still necessary to choose the appropriate optimization scheme according to the actual scenario of the project.
The statistical time
In addition, if we want to check the time consumption of each stage during app startup, we can also set DYLD_PRINT_STATISTICS to 1 in Xcode’s Edit scheme to print the startup time, for example
Startup duration before optimization:
Startup duration after optimization:
Of course, we can only view and print these logs during the development and debugging phase. Then in actual projects, we need to monitor the startup data of online projects so as to locate and optimize those links that affect the startup time of app in a timely manner. At this time, how should we deal with it better?
Of course, we can do our own statistical analysis by reporting buried points of the server, but in this way, we will find that our statistical cost will greatly increase, and the result analysis will become less flexible. Therefore, a simple monitoring method is recommended here, that is, U-APM u-APM should be able to monitor the performance monitoring SDK. After simple POD integration, the startup data can be manually or automatically monitored according to our actual needs. For details, please refer to U-APM. Umeng background has helped us draw the corresponding distribution map according to these data, and we can get the distribution of startup time and the proportion of startup types at a glance, as shown in the figure:
1. Startup time and number of times
2. Distribution of startup time
In addition, we can also carry out crash analysis, ANR analysis, alarm monitoring, lag analysis, memory analysis and many other functions through SDK. In fact, the monitoring platform U-APM has greatly improved our optimization analysis efficiency of online APP in the actual development process. Of course, the introduction of this article is only a relatively shallow optimization items, only for reference and thought guidance, the road to optimization is heavy and long, but also need us to continue to explore, discover, improve. But finally, a word of warning: in the actual project development process, do not optimize for the sake of optimization, to optimize according to the project situation.
Explore the Mach-O file
IOS Basics – Comb through the dyLD loading process from scratch
IOS APP startup – Dyld App loading process
wwdc2016optimizin**gappstartuptime.pdf
Author: Wu Yubao