iOS App 啟動(dòng)優(yōu)化
前言
作為程序猿來(lái)說(shuō),“性能優(yōu)化”是我們都很熟悉的詞,也是我們需要不斷努以及持續(xù)進(jìn)的事情;其實(shí)優(yōu)化是個(gè)很?chē)?yán)謹(jǐn)?shù)恼n題,因?yàn)榧?xì)分來(lái)說(shuō)的話有種優(yōu)化向 ,但是切忌在實(shí)際開(kāi)發(fā)過(guò)程中不能盲目的為了優(yōu)化而優(yōu)化,這樣有時(shí)可能會(huì)造成適得其反的負(fù)效果,需要我們根據(jù)實(shí)際場(chǎng)景以及業(yè)務(wù)需求進(jìn)合理優(yōu)化。接下來(lái)進(jìn)入正題,本文將會(huì)以iOS App的啟動(dòng)優(yōu)化為展開(kāi)點(diǎn)進(jìn)探討。
啟動(dòng)流程:
iOS App 的啟動(dòng)我們都知道分為pre-main 和 main() 兩個(gè)階段,并且在這兩個(gè)階段中,系統(tǒng)會(huì)進(jìn)行系列的加載操作,過(guò)程如下:
1、pre-main階段
1. 加載應(yīng)的可執(zhí)件
2. 加載dyld動(dòng)態(tài)連接器
3. dyld遞歸加載應(yīng)所有依賴(lài)的動(dòng)態(tài)鏈接庫(kù)dylib
2、main()階段
1. dyld調(diào) main()
2. 調(diào)UIApplicationMain()
3. 調(diào)applicationWillFinishLaunching
4. 調(diào)didFinishLaunchingWithOptions
階段優(yōu)化項(xiàng)
1、pre-main階段
針對(duì) pre-main 階段做優(yōu)化時(shí),我們需要先詳細(xì)了解其加載過(guò)程,這個(gè)可以在2016年WWDC 的 Optimizing App Startup Time 中詳細(xì)了解到, 相關(guān)材料
1.1 Load dylibs
這階段dyld分析應(yīng)依賴(lài)的 dylib (xcode7以后.dylib已改為名.tbd),找到其 mach-o 件,打開(kāi)和讀取這些件并驗(yàn)證其有效性,接著會(huì)找到代碼簽名注冊(cè)到內(nèi)核,最后對(duì) dylib 的每個(gè) segment 調(diào) mmap()。不過(guò)這的 dylib 部分都是系統(tǒng)庫(kù),不需要我們?nèi)プ鲱~外的優(yōu)化。
優(yōu)化結(jié)論
1.2 Rebase/Bind
在dylib的加載過(guò)程中,系統(tǒng)為了安全考慮,引了ASLR (Address Space Layout Randomization)技術(shù)和 代碼簽名。由于ASLR的存在,鏡像(Image,包括可執(zhí)件、 dylib和bundle)會(huì)在隨機(jī)的地址上加載,和 之前指針指向的地址(preferred_address)會(huì)有個(gè)偏差(slide), dyld需要修正這個(gè)偏差,來(lái)指向正確的 地址。 Rebase在前, Bind在后, Rebase做的是將鏡像讀內(nèi)存,修正鏡像內(nèi)部的指針,性能消耗主要在 IO。 Bind做的是查詢符號(hào)表,設(shè)置指向鏡像外部的指針,性能消耗主要在CPU計(jì)算。
優(yōu)化結(jié)論:
1.3 Objc setup
部分ObjC初始化作已經(jīng)在Rebase/Bind階段做完了,這步dyld會(huì)注冊(cè)所有聲明過(guò)的ObjC類(lèi),將分類(lèi)插 到類(lèi)的法列表,再檢查每個(gè)selector的唯性。
在這步倒沒(méi)什么優(yōu)化可做的, Rebase/Bind階段優(yōu)化好了,這步的耗時(shí)也會(huì)減少。
1.4 Initializers
在這階段, dyld開(kāi)始運(yùn)程序的初始化函數(shù),調(diào)每個(gè)Objc類(lèi)和分類(lèi)的+load法,調(diào)C/C++ 中的構(gòu)造器 函數(shù)(attribute((constructor))修飾的函數(shù)),和創(chuàng)建基本類(lèi)型的C++靜態(tài)全局變量。 Initializers階段執(zhí) 完后, dyld開(kāi)始調(diào)main()函數(shù)。
優(yōu)化結(jié)論:
2、main()階段
在這階段,主要優(yōu)化重點(diǎn)放在 SDK初始化、業(yè)務(wù)具注冊(cè)、整體
didFinishLaunchingWithOptions 法中,因?yàn)槲覀兊男┑谌?app 格配置、啟動(dòng)引導(dǎo)顯示狀態(tài)邏輯、版本更新邏輯等等基本都會(huì)在這進(jìn),如果這部分邏輯沒(méi)有做好優(yōu)化梳理,隨著業(yè)務(wù)不斷拓展,臃腫的業(yè)務(wù)邏輯會(huì)直接導(dǎo)致啟動(dòng)時(shí) 間加。
場(chǎng)景補(bǔ)充:
另外,在我們實(shí)際開(kāi)發(fā)過(guò)程中,很多項(xiàng)的控制器都會(huì)有些后臺(tái)可配、較為豐富的結(jié)構(gòu)或者推薦數(shù)據(jù) 進(jìn)展示,且我們的展示速度通常也會(huì)被納啟動(dòng)優(yōu)化的部分,其實(shí)對(duì)于這種類(lèi)型的優(yōu)化,如果我 們還只是傳統(tǒng)的 api -> data -> UI 式進(jìn)的話,就很難有明顯的改善空間,因?yàn)閼舻慕j(luò)狀態(tài) 并不是可控項(xiàng),如果不做其他處理的話,那在很多場(chǎng)景下對(duì)戶來(lái)說(shuō),即使我們放上些占位圖,展示的樣式也是很不友好的,畢竟控制器對(duì)戶的第視覺(jué)沖擊影響還是較的。
對(duì)于這種場(chǎng)景下的優(yōu)化來(lái)說(shuō),般我們可以采取 Local + Network + Update 的式在定程度上優(yōu)化 加載速度: 即:
這樣做的好處是
當(dāng)然這種也并不是唯的應(yīng)對(duì)式,且也并對(duì)所有場(chǎng)景都適,只是提供種思路已,還是需要根據(jù) 項(xiàng)的實(shí)際場(chǎng)景選擇適合的優(yōu)化案。
統(tǒng)計(jì)時(shí)
另外如果在開(kāi)發(fā)過(guò)程中,我們想直觀的查看 app 啟動(dòng)期間,各階段的耗時(shí)情況,也可以在Xcode,的 edit scheme 設(shè)置添加 DYLD_PRINT_STATISTICS 為1 ,打印啟動(dòng)時(shí),例如
優(yōu)化前啟動(dòng)時(shí):
優(yōu)化后啟動(dòng)時(shí):
當(dāng)然,這些log我們僅僅只能在開(kāi)發(fā)調(diào)試階段查看打印,那么在實(shí)際項(xiàng)中,我們需要對(duì)線上項(xiàng)的啟動(dòng)數(shù)據(jù) 進(jìn)監(jiān)控,以便及時(shí)的定位和優(yōu)化那些影響 app 啟動(dòng)時(shí)的環(huán)節(jié),這時(shí)我們應(yīng)該怎樣更好的處理呢?
當(dāng)然我們可以通過(guò)服務(wù)器埋點(diǎn)上報(bào)的式統(tǒng)計(jì)分析,不過(guò)這樣來(lái)會(huì)發(fā)現(xiàn)我們的統(tǒng)計(jì)成本就會(huì)增 加,且結(jié)果分析也會(huì)變得不那么靈活。所以這推薦種簡(jiǎn)單的監(jiān)控式,那就是友盟的 U-APM 應(yīng)能性 能監(jiān)控SDK ,只需要我們進(jìn)簡(jiǎn)單的pod集成之后,便可根據(jù)我們的實(shí)際需要進(jìn)動(dòng)或者動(dòng)監(jiān)控啟動(dòng)數(shù) 據(jù),詳情可以參考 U-APM, 并且為了便我們對(duì)數(shù)據(jù)進(jìn)分析,友盟后臺(tái)已經(jīng)根據(jù)這些數(shù)據(jù)幫我們繪制出 了對(duì)應(yīng)的分布圖,我們可以了然的得出啟動(dòng)耗時(shí)分布、啟動(dòng)類(lèi)型占等等,如圖:
除此之外,我們還可以通過(guò)SDK進(jìn)崩潰分析、 ANR分析、監(jiān)控告警、卡頓分析、內(nèi)存分析等等諸多功能, 有了 U-APM 這個(gè)監(jiān)控平臺(tái),其實(shí)在實(shí)際開(kāi)發(fā)過(guò)程中很程度的提升了我們對(duì)線上 app 的優(yōu)化分析效率。
當(dāng)然本的介紹也只是較淺顯的優(yōu)化項(xiàng),僅供參考以及思路引導(dǎo),優(yōu)化之路任重道遠(yuǎn),還需要我們不斷 的去探索、發(fā)現(xiàn)、提。不過(guò)最后還是要提醒句:在實(shí)際項(xiàng)開(kāi)發(fā)過(guò)程中,不要為了優(yōu)化優(yōu)化,要根據(jù) 項(xiàng)情況有針對(duì)性的進(jìn)優(yōu)化。