本篇文章我們主要來探討,iOS應(yīng)用在冷啟動的過程中,做了哪些操作。
首先我們現(xiàn)在工程中增加 DYLD_PRINT_STATISTICS環(huán)境變量,來觀察冷啟動的操作步驟

當(dāng)我們運行工程,等到App啟動之后,我們可以在控制臺看到以下輸出
Total pre-main time: 362.19 milliseconds (100.0%)
dylib loading time: 120.78 milliseconds (33.3%)
rebase/binding time: 126687488.8 seconds (368510566.2%)
ObjC setup time: 57.95 milliseconds (16.0%)
initializer time: 267.55 milliseconds (73.8%)
slowest intializers :
libSystem.B.dylib : 13.15 milliseconds (3.6%)
libBacktraceRecording.dylib : 7.67 milliseconds (2.1%)
libMainThreadChecker.dylib : 234.39 milliseconds (64.7%)
-
dylib loading time:動態(tài)庫加載花費的時間。 -
rebase/binding:rebase:偏移修正,binding:代表符號綁定。 -
ObjC setup time: OC類注冊的耗時。 -
initializer time:load函數(shù)和構(gòu)造函數(shù)的耗時。
dyld loading
加載動態(tài)庫:Dyld從主執(zhí)行文件的header獲取到需要加載的所依賴動態(tài)庫列表,然后它需要找到每個dyld,而應(yīng)用所依賴的dylib文件可能會再依賴其他dylib,所以需要加載的是動態(tài)庫列表一個遞歸依賴的集合。
Rebase 和 Bind
什么是偏移修正?
我們的App會編譯為一個二進制文件,里面的方法,函數(shù)調(diào)用等元素的地址都是相對于二進制文件的,當(dāng)我們的程序運行到內(nèi)存時,系統(tǒng)的 安全機制,會生成一個內(nèi)存偏移值(ASLR)。根據(jù) ASLR的值和函數(shù)的相對值,我們就可以得到該方法在內(nèi)存中的實際地址值。舉個??,假設(shè) funcA在二進制文件中的地址值為0x0001,系統(tǒng)給的 ASLR(安全機制隨機的值)為 0x1000,則funcA在運行時的內(nèi)存地址值則為0x0001 + 0x1000 = 0x1001
什么是符號綁定?
我們在代碼中的每一個函數(shù)在編譯之后,都會在MachO文件中創(chuàng)建相對應(yīng)的符號,在載入內(nèi)存時,會將符號與相對應(yīng)的內(nèi)存進行一對一的關(guān)聯(lián)。舉個??:假設(shè)我們在代碼中寫了如下函數(shù)NSLog(@"123"),編譯之后,在MachO二進制文件中,會創(chuàng)建一個符號NSLog,在載入內(nèi)存后,該符號會和NSLog地址進行綁定。這個過程叫做符號綁定。
Objc setup
- 注冊O(shè)bjc類(class registration)
- 把category的定義插入方法列表(category registration)
- 保證每一個
selector唯一。
initializers
- Objc的
+load()函數(shù)。 - C++的構(gòu)造函數(shù)。
通過以上分析,我們可以知道,動態(tài)庫的加載,OC類的多少和 load函數(shù)等等,都會影響我們的pre-main的耗時。蘋果官方推薦的最佳動態(tài)庫的數(shù)量為 6個,為了減少pre-main的耗時,我們要減少 load方法的使用,我們項目中不使用的OC類和method需要移除。另外還要減少C++中虛函數(shù)的使用,以減少 initializer的耗時。通過這些操作來優(yōu)化iOS冷啟動的時間。