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

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