需要花費(fèi)5分鐘的閱讀時(shí)間
基本大綱
- 應(yīng)用的啟動(dòng)分為Pre-main和mian兩部分
- 在Pre-main中,可以大致分為load dylib->rebase->bind->Objc setup-> initializer故爵,開發(fā)能掌握和度量的是initializer部分
- 在開發(fā)階段(Xcode)如何查看啟動(dòng)的每個(gè)階段的時(shí)間---通過在Xcode中超凳,設(shè)置Edit Scheme -> Run -> Argument匯總的環(huán)境變量,會(huì)在console中輸出
- 在應(yīng)用上線后引颈,統(tǒng)計(jì)Pre-mian的使用時(shí)間。利用的在加載動(dòng)態(tài)庫的一個(gè)順序機(jī)制扰才,定制自己的動(dòng)態(tài)庫同波,讓他在第一個(gè)被加載鳄梅,并在load函數(shù)中hook住所有可執(zhí)行文件,然后統(tǒng)計(jì)出最終的每一個(gè)的時(shí)間未檩,得到最后的時(shí)間(后續(xù)文章具體講述)
- Class Load 和 Static Initializers(+(void)load; + (void)initialize; 后續(xù)文章)
- Xcode For Static Initializer
Apple建議
Apple suggest to aim for a total app launch time of under 400ms and you must do it in less than 20 seconds or the system will kill your app.
Apple建議應(yīng)用的啟動(dòng)時(shí)間控制在400ms之下戴尸。并且必須在20s以內(nèi)完成啟動(dòng),否則系統(tǒng)則會(huì)kill掉應(yīng)用程序冤狡。那么話說我們?nèi)绾沃繿pp的在啟動(dòng)到調(diào)用main()方法之前的時(shí)間呢孙蒙?在WWDC 2016的提到了這方面的信息。
Pre-main時(shí)間
從在屏幕上點(diǎn)擊你的app icon開始悲雳,到應(yīng)用執(zhí)行到main()
方法或者執(zhí)行到applicationWillFinishLaunching
的過程中挎峦,app執(zhí)行了一系列的操作。在iOS10之前的系統(tǒng)中合瓢,我們無處得知其中的細(xì)節(jié)坦胶。而在iOS10系統(tǒng)中,可以通過簡單在Xcode設(shè)置晴楔,在控制臺(tái)就可以打印出Pre-main的具體信息細(xì)節(jié)顿苇。
通過Xcode中的Edit Scheme -> Run -> Argument
,設(shè)置參數(shù)DYLD_PRINT_STATISTICS
值為1
這里使用的Objective-C項(xiàng)目税弃,iPad Air2岖圈,系統(tǒng)iOS10.3
Total pre-main time: 74.37 milliseconds (100.0%)
dylib loading time: 41.05 milliseconds (55.2%)
rebase/binding time: 8.10 milliseconds (10.9%)
ObjC setup time: 9.87 milliseconds (13.2%)
initializer time: 15.23 milliseconds (20.4%)
slowest intializers :
libSystem.B.dylib : 6.58 milliseconds (8.8%)
libBacktraceRecording.dylib : 6.27 milliseconds (8.4%)
上文中可以看出總共消耗的時(shí)間為74.37ms。
dylib loading time 載入動(dòng)態(tài)庫钙皮,這個(gè)過程中蜂科,會(huì)去裝載app使用的動(dòng)態(tài)庫,而每一個(gè)動(dòng)態(tài)庫有它自己的依賴關(guān)系短条,所以會(huì)消耗時(shí)間去查找和讀取导匣。對(duì)于Apple提供的的系統(tǒng)動(dòng)態(tài)庫,做了高度的優(yōu)化茸时。而對(duì)于開發(fā)者定義導(dǎo)入的動(dòng)態(tài)庫贡定,則需要在花費(fèi)更多的時(shí)間。Apple官方建議盡量少的使用自定義的動(dòng)態(tài)庫可都,或者考慮合并多個(gè)動(dòng)態(tài)庫缓待,其中一個(gè)建議是當(dāng)大于6個(gè)的時(shí)候,則需要考慮合并它們
rebase/binding time 重構(gòu)和綁定渠牲,rebase會(huì)修正調(diào)整處理圖像的指針旋炒,并且會(huì)設(shè)置指向綁定(binding)外部的圖像指針。所以為了加快rebase/binding签杈,則需要更少的做指針修復(fù)瘫镇。當(dāng)你的app當(dāng)中有太多的Objective-C的類,方法選擇器,和類別會(huì)增加這一部分的啟動(dòng)時(shí)間铣除。有一個(gè)數(shù)據(jù)當(dāng)大于20000個(gè)時(shí)候谚咬,會(huì)增加800ms的時(shí)間。另一點(diǎn):當(dāng)你的app中使用了很少的C++的虛擬函數(shù)尚粘,使用Swift會(huì)更加高效
ObjC setup time 在Objective-C的運(yùn)行時(shí)(runtime)择卦,需要對(duì)類(class),類別(category)進(jìn)行注冊(cè)郎嫁,以及選擇器的分配秉继,所以參照rebase/binding time,盡量減少類的數(shù)量行剂,可以達(dá)到減少這一部分的時(shí)間
initializer time 這一份指代的是執(zhí)行
+initialize
方法的時(shí)間秕噪。如果你執(zhí)行了+load
方法(不建議),盡量使用+initialize
代替厚宰。
加載框架使用的時(shí)間 - dylib loading time
這里使用一個(gè)快速的實(shí)驗(yàn)驗(yàn)證加載框架產(chǎn)生的時(shí)間變化腌巾。這里基于iPad Air2,系統(tǒng)iOS10.3铲觉。
-
新建一個(gè)Swift項(xiàng)目澈蝙,并且每一次重啟設(shè)備,保證沒有應(yīng)用緩存撵幽。
Total pre-main time: 408.97 milliseconds (100.0%) dylib loading time: 383.84 milliseconds (93.8%) rebase/binding time: 7.86 milliseconds (1.9%) ObjC setup time: 6.82 milliseconds (1.6%) initializer time: 10.36 milliseconds (2.5%) slowest intializers : libSystem.B.dylib : 2.33 milliseconds (0.5%)
可以看到載入框架的時(shí)間在380ms之上灯荧,相比于Objective項(xiàng)目增加了很多。我的猜測(cè)是由于載入了Swift的dylib盐杂。
-
在項(xiàng)目中導(dǎo)入10個(gè)外部的dylib(Swift cocoapods)
Total pre-main time: 682.90 milliseconds (100.0%) dylib loading time: 631.17 milliseconds (92.4%) rebase/binding time: 17.06 milliseconds (2.4%) ObjC setup time: 17.47 milliseconds (2.5%) initializer time: 17.09 milliseconds (2.5%) slowest intializers : libSystem.B.dylib : 6.05 milliseconds (0.8%)
由上可知逗载,dylib加載的時(shí)間從380ms上升到了630ms,這不是一個(gè)很科學(xué)的實(shí)驗(yàn)链烈,不過也應(yīng)該意識(shí)到加載外部的dylib對(duì)加載時(shí)間有比較大的影響厉斟。