iOS app啟動(dòng)時(shí)間

應(yīng)用啟動(dòng)流程

iOS應(yīng)用啟動(dòng)可以分為pre-main階段和main()階段

pre-main階段
  • 1.1. 加載應(yīng)用的可執(zhí)行文件
  • 1.2. 加載動(dòng)態(tài)鏈接庫(kù)加載器dyld(dynamic loader)
  • 1.3. dyld遞歸加載應(yīng)用所有依賴的dylib(dynamic library 動(dòng)態(tài)鏈接庫(kù))
main()階段
  • 2.1. dyld調(diào)用main()
  • 2.2. 調(diào)用UIApplicationMain()
  • 2.3. 調(diào)用applicationWillFinishLaunching
  • 2.4. 調(diào)用didFinishLaunchingWithOptions
  1. pre-main階段

對(duì)于pre-main階段,Apple提供了一種測(cè)量方法,在 Xcode 中 Edit scheme -> Run -> Auguments 將環(huán)境變量DYLD_PRINT_STATISTICS 設(shè)為1 。之后控制臺(tái)會(huì)輸出類似內(nèi)容:

Total pre-main time: 217.57 milliseconds (100.0%)
         dylib loading time:  29.38 milliseconds (13.5%)
        rebase/binding time:  12.15 milliseconds (5.5%)
            ObjC setup time:  16.71 milliseconds (7.6%)
           initializer time: 159.09 milliseconds (73.1%)
           slowest intializers :
             libSystem.B.dylib :   4.17 milliseconds (1.9%)
    libMainThreadChecker.dylib :  34.80 milliseconds (15.9%)
          libglInterpose.dylib :  53.05 milliseconds (24.3%)
         libMTLInterpose.dylib :  14.19 milliseconds (6.5%)
                       ZhouDao :  89.54 milliseconds (41.1%)

這樣我們可以清晰的看到每個(gè)耗時(shí)了。

2.main()階段

mian()階段主要是測(cè)量mian()函數(shù)開始執(zhí)行到didFinishLaunchingWithOptions執(zhí)行結(jié)束的時(shí)間,我們直接插入代碼就可以了

CFAbsoluteTime StartTime; 
int main(int argc, char * argv[]) { 
StartTime = CFAbsoluteTimeGetCurrent(); 

到主UI框架的.m文件用extern聲明全局變量StartTime

extern CFAbsoluteTime StartTime; 

在viewDidAppear函數(shù)里,再獲取一下當(dāng)前時(shí)間,與StartTime的差值即是main()階段運(yùn)行耗時(shí)。

double launchTime = (CFAbsoluteTimeGetCurrent() - StartTime); 

[HomeViewController viewDidAppear:] launchTime:0.619898

改善啟動(dòng)時(shí)間

pre-main階段

在這一階段,我們能做的主要是優(yōu)化dylib

加載 Dylib

之前提到過加載系統(tǒng)的 dylib 很快,因?yàn)橛袃?yōu)化。但加載內(nèi)嵌(embedded)的 dylib 文件很占時(shí)間,所以盡可能把多個(gè)內(nèi)嵌 dylib 合并成一個(gè)來加載,或者使用 static archive。

使用 dlopen() 來在運(yùn)行時(shí)懶加載是不建議的,這么做可能會(huì)帶來一些問題,并且總的開銷更大。

Rebase/Binding

之前提過 Rebaing 消耗了大量時(shí)間在 I/O 上,而在之后的 Binding 就不怎么需要 I/O 了,而是將時(shí)間耗費(fèi)在計(jì)算上。所以這兩個(gè)步驟的耗時(shí)是混在一起的。

之前說過可以從查看 __DATA 段中需要修正(fix-up)的指針,所以減少指針數(shù)量才會(huì)減少這部分工作的耗時(shí)。對(duì)于 ObjC 來說就是減少 Class,selector 和 category 這些元數(shù)據(jù)的數(shù)量。從編碼原則和設(shè)計(jì)模式之類的理論都會(huì)鼓勵(lì)大家多寫精致短小的類和方法,并將每部分方法獨(dú)立出一個(gè)類別,其實(shí)這會(huì)增加啟動(dòng)時(shí)間。對(duì)于 C++ 來說需要減少虛方法,因?yàn)樘摲椒〞?huì)創(chuàng)建 vtable,這也會(huì)在 __DATA 段中創(chuàng)建結(jié)構(gòu)。雖然 C++ 虛方法對(duì)啟動(dòng)耗時(shí)的增加要比 ObjC 元數(shù)據(jù)要少,但依然不可忽視。

Objc setup

大部分ObjC初始化工作已經(jīng)在Rebase/Bind階段做完了,這一步dyld會(huì)注冊(cè)所有聲明過的ObjC類,將分類插入到類的方法列表里,再檢查每個(gè)selector的唯一性。

在這一步倒沒什么優(yōu)化可做的,Rebase/Bind階段優(yōu)化好了,這一步的耗時(shí)也會(huì)減少。

Initializers

到了這一階段,dyld開始運(yùn)行程序的初始化函數(shù),調(diào)用每個(gè)Objc類和分類的+load方法,調(diào)用C/C++ 中的構(gòu)造器函數(shù)(用attribute((constructor))修飾的函數(shù)),和創(chuàng)建非基本類型的C++靜態(tài)全局變量。Initializers階段執(zhí)行完后,dyld開始調(diào)用main()函數(shù)。

在這一步,我們可以做的優(yōu)化有:

  • 1、少在類的+load方法里做事情,盡量把這些事情推遲到+initiailize
  • 2、減少構(gòu)造器函數(shù)個(gè)數(shù),在構(gòu)造器函數(shù)里少做些事情
  • 3、減少C++靜態(tài)全局變量的個(gè)數(shù)
main()階段的優(yōu)化

這一階段的優(yōu)化主要是減少didFinishLaunchingWithOptions方法里的工作,在didFinishLaunchingWithOptions方法里,我們會(huì)創(chuàng)建應(yīng)用的window,指定其rootViewController,調(diào)用window的makeKeyAndVisible方法讓其可見。由于業(yè)務(wù)需要,我們會(huì)初始化各個(gè)二方/三方庫(kù),設(shè)置系統(tǒng)UI風(fēng)格,檢查是否需要顯示引導(dǎo)頁(yè)、是否需要登錄、是否有新版本等,由于歷史原因,這里的代碼容易變得比較龐大,啟動(dòng)耗時(shí)難以控制。

所以,滿足業(yè)務(wù)需要的前提下,didFinishLaunchingWithOptions在主線程里做的事情越少越好。在這一步,我們可以做的優(yōu)化有:

  • 1、梳理各個(gè)二方/三方庫(kù),找到可以延遲加載的庫(kù),做延遲加載處理,比如放到首頁(yè)控制器的viewDidAppear方法里。
  • 2、梳理業(yè)務(wù)邏輯,把可以延遲執(zhí)行的邏輯,做延遲執(zhí)行處理。比如檢查新版本、注冊(cè)推送通知等邏輯。
  • 3、避免復(fù)雜/多余的計(jì)算。
  • 4、避免在首頁(yè)控制器的viewDidLoad和viewWillAppear做太多事情,這2個(gè)方法執(zhí)行完,首頁(yè)控制器才能顯示,部分可以延遲創(chuàng)建的視圖應(yīng)做延遲創(chuàng)建/懶加載處理。
  • 5、首頁(yè)控制器用純代碼方式來構(gòu)建。
總結(jié)

總結(jié)起來,好像啟動(dòng)速度優(yōu)化就一句話:讓系統(tǒng)在啟動(dòng)期間少做一些事。當(dāng)然我們得先清楚工程里做的哪些事是在啟動(dòng)期間做的、對(duì)啟動(dòng)速度的影響有多大,然后case by case地分析工程代碼,通過放到子線程、延遲加載、懶加載等方式讓系統(tǒng)在啟動(dòng)期間更輕松些。

轉(zhuǎn)自:http://mobile.51cto.com/hot-584384.htm

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,797評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,179評(píng)論 3 414
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 175,628評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,642評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,444評(píng)論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,948評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,040評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,185評(píng)論 0 287
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,717評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,602評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,794評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評(píng)論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,045評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,418評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評(píng)論 1 281
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,414評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,750評(píng)論 2 370

推薦閱讀更多精彩內(nèi)容

  • 背景 99u在去年做過一次加快啟動(dòng)時(shí)間的優(yōu)化,雖然是工廠大大們?cè)谥鲗?dǎo),但是一直很好奇當(dāng)我們的手指在屏幕上點(diǎn)擊一個(gè)a...
    d8893ea8ba05閱讀 3,421評(píng)論 2 11
  • 在用戶打開App的時(shí)候,過長(zhǎng)的等待時(shí)間會(huì)使用戶陷入等待焦慮,對(duì)用戶留存率產(chǎn)生不良影響,雖然精致的啟動(dòng)頁(yè)能對(duì)等待焦慮...
    Don_He閱讀 1,807評(píng)論 0 0
  • 程序和進(jìn)程 廣義上的程序就是一個(gè)靜態(tài)的可執(zhí)行文件,是由一個(gè)已經(jīng)編譯好的指令和數(shù)據(jù)集合的一個(gè)文件。就像是我們通過Xc...
    Klaus_J閱讀 4,239評(píng)論 1 11
  • 1 dyld 1.1 dyld簡(jiǎn)介 在iOS系統(tǒng)中,幾乎所有的程序都會(huì)用到動(dòng)態(tài)庫(kù),而動(dòng)態(tài)庫(kù)在加載的時(shí)候都需要用d...
    Kevin_Junbaozi閱讀 11,908評(píng)論 4 44
  • 本文介紹App啟動(dòng)性能優(yōu)化,共分五個(gè)部分: 第一部分App啟動(dòng)過程 第二部分pre-main階段的過程和可優(yōu)化項(xiàng) ...
    小飛魚_love閱讀 16,803評(píng)論 1 69