iOS App 啟動優(yōu)化

技術(shù)調(diào)研

啟動時間計算公式

App總啟動時間 = t1(main()之前的加載時間) + t2(main()之后的加載時間)豌鸡。

t1 = 系統(tǒng)dylib(動態(tài)鏈接庫)和自身App可執(zhí)行文件的加載;

t2 = main方法執(zhí)行之后到AppDelegate類中的- (BOOL)Application:(UIApplication *)Application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions方法執(zhí)行結(jié)束前這段時間,主要是構(gòu)建第一個界面凰慈,并完成渲染展示。

啟動流程

main()調(diào)用之前加載過程

exec() 是一個系統(tǒng)調(diào)用。系統(tǒng)內(nèi)核把應用映射到新的地址空間,且每次起始位置都是隨機的(因為使用 ASLR)逸爵。并將起始位置到 0x000000 這段范圍的進程權(quán)限都標記為不可讀寫不可執(zhí)行。如果是 32 位進程凹嘲,這個范圍至少是 4KB师倔;對于 64 位進程則至少是 4GB。NULL 指針引用和指針截斷誤差都是會被它捕獲周蹭。

dylib loading

從主執(zhí)行文件的 header 獲取到需要加載的所依賴動態(tài)庫列表趋艘,而 header 早就被內(nèi)核映射過。然后它需要找到每個 dylib凶朗,然后打開文件讀取文件起始位置瓷胧,確保它是 Mach-O 文件。接著會找到代碼簽名并將其注冊到內(nèi)核棚愤。然后在 dylib 文件的每個 segment 上調(diào)用 mmap()搓萧。應用所依賴的 dylib 文件可能會再依賴其他 dylib,所以 dyld 所需要加載的是動態(tài)庫列表一個遞歸依賴的集合宛畦。一般應用會加載 100 到 400 個 dylib 文件瘸洛,但大部分都是系統(tǒng) dylib,它們會被預先計算和緩存起來次和,加載速度很快货矮。

rebase/bind

由于ASLR(address space layout randomization)的存在,可執(zhí)行文件和動態(tài)鏈接庫在虛擬內(nèi)存中的加載地址每次啟動都不固定斯够,所以需要這2步來修復鏡像中的資源指針,來指向正確的地址喧锦。 rebase修復的是指向當前鏡像內(nèi)部的資源指針读规; 而bind指向的是鏡像外部的資源指針。

rebase步驟先進行燃少,需要把鏡像讀入內(nèi)存束亏,并以page為單位進行加密驗證,保證不會被篡改阵具,所以這一步的瓶頸在IO碍遍。bind在其后進行,由于要查詢符號表阳液,來指向跨鏡像的資源怕敬,加上在rebase階段,鏡像已被讀入和加密驗證帘皿,所以這一步的瓶頸在于CPU計算东跪。

通過命令行可以查看相關(guān)的資源指針:

xcrun dyldinfo -rebase -bind -lazy_bind myApp.App/myApp

優(yōu)化該階段的關(guān)鍵在于減少__DATA segment中的指針數(shù)量。我們可以優(yōu)化的點有:

  1. 減少Objc類數(shù)量, 減少selector數(shù)量

  2. 減少C++虛函數(shù)數(shù)量

  3. 轉(zhuǎn)而使用swift struct(其實本質(zhì)上就是為了減少符號的數(shù)量)

Objc Runtime

這一步主要工作是:

  1. 注冊O(shè)bjc類 (class registration)

  2. 把category的定義插入方法列表 (category registration)

  3. 保證每一個selector唯一 (selctor uniquing)

由于之前2步驟的優(yōu)化虽填,這一步實際上沒有什么可做的丁恭。

initializers

以上三步屬于靜態(tài)調(diào)整(fix-up),都是在修改__DATA segment中的內(nèi)容斋日,而這里則開始動態(tài)調(diào)整牲览,開始在堆和堆棧中寫入內(nèi)容。 在這里的工作有:

  1. Objc的+load()函數(shù),使用 +initialize 來替代 +load

  2. C++的構(gòu)造函數(shù)屬性函數(shù) 形如attribute((constructor)) void DoSomeInitializationWork()

  3. 非基本類型的C++靜態(tài)全局變量的創(chuàng)建(通常是類或結(jié)構(gòu)體)(non-trivial initializer) 比如一個全局靜態(tài)結(jié)構(gòu)體的構(gòu)建恶守,如果在構(gòu)造函數(shù)中有繁重的工作第献,那么會拖慢啟動速度

Objc的load函數(shù)和C++的靜態(tài)構(gòu)造函數(shù)采用由底向上的方式執(zhí)行,來保證每個執(zhí)行的方法熬的,都可以找到所依賴的動態(tài)庫痊硕。

main()調(diào)用之后的加載時間

在main()被調(diào)用之后,App的主要工作就是初始化必要的服務(wù)押框,顯示首頁內(nèi)容等岔绸。而我們的優(yōu)化也是圍繞如何能夠快速展現(xiàn)首頁來開展。 App通常在AppDelegate類中的- (BOOL)Application:(UIApplication *)Application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions方法中創(chuàng)建首頁需要展示的view橡伞,然后在當前runloop的末尾盒揉,主動調(diào)用CA::Transaction::commit完成視圖的渲染。

而視圖的渲染主要涉及三個階段:

準備階段 這里主要是圖片的解碼

布局階段 首頁所有UIView的- (void)layoutSubViews()運行

繪制階段 首頁所有UIView的- (void)drawRect:(CGRect)rect運行

再加上啟動之后必要服務(wù)的啟動兑徘、必要數(shù)據(jù)的創(chuàng)建和讀取刚盈,這些就是我們可以嘗試優(yōu)化的地方

因此,main()函數(shù)調(diào)用之前我們可以優(yōu)化的點有:

不使用xib挂脑,直接視用代碼加載首頁視圖藕漱。

NSUserDefaults實際上是在Library文件夾下會生產(chǎn)一個plist文件,如果文件太大的話一次能讀取到內(nèi)存中可能很耗時崭闲,這個影響需要評估肋联,如果耗時很大的話需要拆分(需考慮老版本覆蓋安裝兼容問題)。

每次用NSLog方式打印會隱式的創(chuàng)建一個Calendar, 僅僅針對內(nèi)測版輸出log刁俭。

梳理應用啟動時發(fā)送的所有網(wǎng)絡(luò)請求橄仍,統(tǒng)一在異步線程請求。

并行初始化各個業(yè)務(wù)牍戚。

優(yōu)化方案

main()調(diào)用之前加載過程,優(yōu)化內(nèi)容
  1. 減少framework引用

  2. 刪除無用類侮繁,無用函數(shù)

  3. 減少+load 函數(shù)使用

main()調(diào)用之后, 優(yōu)化內(nèi)容
  1. 將業(yè)務(wù)相關(guān)的啟動放入group async 內(nèi)進行,并發(fā)期待如孝。

  2. 最后在wait 全部執(zhí)行后宪哩,進行splash 頁面。

  3. 業(yè)務(wù)不相關(guān)的放入全局global_queue 內(nèi)進行初始化

// 自定義queue
dispatch_group_t lanchGroup = dispatch_group_create();
dispatch_queue_t lanchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 全局并行queue
dispatch_group_async(lanchGroup, lanchQueue, ^{});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{});

參考鏈接:https://github.com/hongruqi/WTAppLauncher
參考鏈接https://chars.tech/blog/ios-app-launch-time-optimize/

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末暑竟,一起剝皮案震驚了整個濱河市斋射,隨后出現(xiàn)的幾起案子育勺,更是在濱河造成了極大的恐慌,老刑警劉巖罗岖,帶你破解...
    沈念sama閱讀 216,843評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件涧至,死亡現(xiàn)場離奇詭異,居然都是意外死亡桑包,警方通過查閱死者的電腦和手機南蓬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,538評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來哑了,“玉大人赘方,你說我怎么就攤上這事∪踝螅” “怎么了窄陡?”我有些...
    開封第一講書人閱讀 163,187評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長拆火。 經(jīng)常有香客問我跳夭,道長,這世上最難降的妖魔是什么们镜? 我笑而不...
    開封第一講書人閱讀 58,264評論 1 292
  • 正文 為了忘掉前任币叹,我火速辦了婚禮,結(jié)果婚禮上模狭,老公的妹妹穿的比我還像新娘颈抚。我一直安慰自己,他們只是感情好嚼鹉,可當我...
    茶點故事閱讀 67,289評論 6 390
  • 文/花漫 我一把揭開白布贩汉。 她就那樣靜靜地躺著,像睡著了一般锚赤。 火紅的嫁衣襯著肌膚如雪雾鬼。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,231評論 1 299
  • 那天宴树,我揣著相機與錄音,去河邊找鬼晶疼。 笑死酒贬,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的翠霍。 我是一名探鬼主播锭吨,決...
    沈念sama閱讀 40,116評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼寒匙!你這毒婦竟也來了零如?” 一聲冷哼從身側(cè)響起躏将,我...
    開封第一講書人閱讀 38,945評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎考蕾,沒想到半個月后祸憋,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,367評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡肖卧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,581評論 2 333
  • 正文 我和宋清朗相戀三年蚯窥,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片塞帐。...
    茶點故事閱讀 39,754評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡拦赠,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出葵姥,到底是詐尸還是另有隱情荷鼠,我是刑警寧澤,帶...
    沈念sama閱讀 35,458評論 5 344
  • 正文 年R本政府宣布榔幸,位于F島的核電站允乐,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏牡辽。R本人自食惡果不足惜喳篇,卻給世界環(huán)境...
    茶點故事閱讀 41,068評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望态辛。 院中可真熱鬧麸澜,春花似錦、人聲如沸奏黑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,692評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽熟史。三九已至馁害,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蹂匹,已是汗流浹背碘菜。 一陣腳步聲響...
    開封第一講書人閱讀 32,842評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留限寞,地道東北人忍啸。 一個月前我還...
    沈念sama閱讀 47,797評論 2 369
  • 正文 我出身青樓,卻偏偏與公主長得像履植,于是被迫代替她去往敵國和親计雌。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,654評論 2 354

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

  • 背景 一個項目做的時間長了玫霎,啟動流程往往容易雜亂凿滤,庫也用的越來越多妈橄,APP的啟動時間也會慢慢變長。本次將針對iOS...
    醬油瓶2閱讀 3,509評論 0 12
  • 1.App啟動過程 解析Info.plist加載相關(guān)信息翁脆,例如如閃屏沙箱建立眷蚓、權(quán)限檢查 Mach-O加載如果是胖二...
    音符上的碼字員閱讀 1,304評論 0 4
  • 冷啟動(Cold launch)耗時才是我們需要測量的重要數(shù)據(jù),為了準確測量冷啟動耗時鹃祖,測量前需要重啟設(shè)備溪椎。在 m...
    code_xu閱讀 258評論 0 1
  • 這是一篇 WWDC 2016 Session 406 的學習筆記,從原理到實踐講述了如何優(yōu)化 App 的啟動時間恬口。...
    MTDeveloper閱讀 748評論 0 1
  • App 運行理論 理論速成Mach-O 術(shù)語Mach-O 是針對不同運行時可執(zhí)行文件的文件類型校读。文件類型:Exec...
    未明一二閱讀 546評論 1 3