App啟動分析與優(yōu)化策略

一母赵、?啟動過程分析

1眼溶、解析Info.plist

a.加載相關(guān)信息碍现,例如閃屏

b.沙箱建立、權(quán)限檢查

2米奸、Mach-O加載

Mach-O 文件:我們寫的程序想要跑起來昼接,肯定它的可執(zhí)行文件格式要被操作系統(tǒng)所理解。比如ELF是Linux下的可執(zhí)行文件格式悴晰,那么對于OS X / iOS來說慢睡,Mach-O 是其可執(zhí)行文件格式逐工。

Mach-O格式主要包括以下幾種文件類型:

Executable:應(yīng)用的主要二進制

Dylib:動態(tài)鏈接庫

Bundle:不能被鏈接,只能在運行時使用dlopen加載

Image:包含Executable漂辐、Dylib和Bundle

Framework:包含Dylib泪喊、資源文件和頭文件的文件夾

如果是胖二進制文件,尋找合適當(dāng)前CPU類別的部分

加載所有依賴的Mach-O文件(遞歸調(diào)用Mach-O加載的方法)

定位內(nèi)部髓涯、外部指針引用袒啼,例如字符串、函數(shù)等

執(zhí)行聲明為__attribute__((constructor))的C函數(shù)

加載類擴展(Category)中的方法

C++靜態(tài)對象加載纬纪、調(diào)用ObjC的?+load?函數(shù)

3蚓再、程序執(zhí)行

調(diào)用main()

調(diào)用UIApplicationMain()

調(diào)用applicationWillFinishLaunching

二、測量App的啟動時間

iOS App的啟動有兩種方式:冷啟動和熱啟動包各,下面對這兩種啟動方式進行簡單介紹摘仅。

冷啟動:App第一次啟動或者是被上滑Kill掉之后,再次從點擊App應(yīng)用圖標到App完全啟動顯示主頁面為止的過程成為冷啟動问畅。

熱啟動:當(dāng)用戶從當(dāng)前App按下HOME鍵退出后娃属,系統(tǒng)并不會立即kill掉App的進程,還會繼續(xù)后臺執(zhí)行一段時間(至于什么時候會被kill护姆,完全取決于系統(tǒng)內(nèi)存等資源的使用情況矾端,理想情況下可以保持后臺運行15min)。然后當(dāng)用戶再次點擊App圖標時签则,會很快加載到上次停留的頁面须床,幾乎不需要進行資源載入,這種情況下的啟動成為熱啟動渐裂。

下面我們對于App啟動時間的測量只討論在冷啟動情形下豺旬。根據(jù)蘋果官方介紹,iOS應(yīng)用的啟動分為兩個階段:pre-main和main柒凉,所以App啟動的總時間為:Total Time = pre-main Time + main Time族阅。

Pre-main 階段

Pre-mian 階段即main()函數(shù)被調(diào)用之前的加載時間,包括dylib動態(tài)庫的加載膝捞、Mach-O文件加載坦刀、Rebase/Bining、Objective-C Runtime 加載等蔬咬。該過程如下圖所示:

main 階段

main 階段指的是從調(diào)用main()函數(shù)開始鲤遥,調(diào)用UIApplicationMain()創(chuàng)建UIApplication,AppDelegate,直到回調(diào)App代理方法applicationDidBecomeActive:為止林艘,其中包括application:didFinishLaunchingWithOptions方法中創(chuàng)建keyWindow盖奈、三方sdk和其他初始化項所消耗的時間,也包含RootViewController 的 ChildViewController的view完全顯示出來所花費的時間狐援。該過程如下圖所示:

main 階段時間測量

那么對于pre-main?和?main?啟動階段的耗時如何測量呢钢坦?蘋果已為我們提供了一個簡單易用的測試方法:在Xcode中選中項目的Scheme→?Edit Scheme...→究孕,然后選擇Run→Arguments→Environment Variables中添加Name =?DYLD_PRINT_STATISTICSvalue,Value = 1 的環(huán)境變量爹凹。如下圖所示:

然后重新運行項目厨诸,注意控制臺下面的打印輸出,格式為:

Totalpre-main time:655.68milliseconds (100.0%)

dylib loading time:205.67milliseconds (31.3%)

rebase/binding time:320.95milliseconds (48.9%)

ObjCsetup time:63.07milliseconds (9.6%)

initializer time:65.85milliseconds (10.0%)

? ? ? ? ? slowest intializers :

libSystem.B.dylib :3.43milliseconds (0.5%)

libMainThreadChecker.dylib :15.59milliseconds (2.3%)

century :76.56milliseconds (11.6%)


Totalpre-main time:? 表示pre-main階段總的時間消耗為655.68毫秒

dylib loading time: 動態(tài)庫加載時間

rebase/binding time: 重定位指針指向/指向鏡像外部內(nèi)容 所需時間

ObjCsetup time:ObjC初始化時間

initializer time: 其他初始化時間的總和

slowest intializers : 最慢的三個初始化分別是libSystem.B.dylib禾酱、libMainThreadChecker.dylib微酬、century(項目名稱)

main 階段時間測量

由于main階段涉及到大量的自定義代碼,app主體頁面的初始化宇植、前期配置得封、三方庫初始化等大量邏輯代理,iOS系統(tǒng)沒有直接的測量方式指郁,所以只能通過打點的方式計算啟動開始到啟動結(jié)束的時間差即可忙上。例如下面示例代碼:

// main.m 文件

#import"AppDelegate.h"

externCFAbsoluteTimeStartTime;

intmain(intargc,char* argv[]) {

// 記錄開始時間

StartTime =CFAbsoluteTimeGetCurrent();

@autoreleasepool{

returnUIApplicationMain(argc, argv,nil,NSStringFromClass([AppDelegateclass]));

? ? }

}

// AppDelegate.m 文件

CFAbsoluteTimeStartTime;

- (void)applicationDidBecomeActive:(UIApplication*)application {

dispatch_async(dispatch_get_main_queue(), ^{

NSUIntegermilliseconds = (NSUInteger)((CFAbsoluteTimeGetCurrent() - StartTime) *1000);

NSLog(@"Loading done in %lu ms", milliseconds);

? ? });

}


影響啟動性能的因素

接下來我們討論在App啟動的pre-main階段和mian階段,影響啟動性能的多種因素闲坎。

Pre-main 階段

動態(tài)庫加載越多疫粥,啟動越慢。

ObjC類越多腰懂,啟動越慢

C的constructor函數(shù)越多梗逮,啟動越慢

C++靜態(tài)對象越多,啟動越慢

ObjC的+load方法使用越多绣溜,啟動越慢

我們盡量不要寫__attribute__((constructor))的C函數(shù)慷彤,也盡量不要用到C++的靜態(tài)對象;至于ObjC的+load方法怖喻,似乎大家已經(jīng)習(xí)慣不用它了底哗。任何情況下,能用dispatch_once()來完成的锚沸,就盡量不要用到以上的方法跋选。

main 階段

執(zhí)行main()函數(shù)的耗時

執(zhí)行application:didFinishLaunchingWithOptions的耗時

rootViewController及其childViewController的加載、view及其subviews的加載

一般的App的主體UI架構(gòu)是哗蜈,UITabbarViewController?作為?keyWindow的根控制器前标,然后包含多個ChildViewController作為每個tab的根控制器。然而在didFinishLaunchingWithOptions代理方法中各控制器的初始化順序是怎樣的呢距潘?

答案是:

-[MQQTabBarController viewDidLoad]

-[MQQTab1ViewController viewDidLoad]

-[AppDelegate application:didFinishLaunchingWithOptions:]

-[MQQTab2ViewController viewDidLoad]?(點擊了第二個tab之后加載)

-[MQQTab3ViewController viewDidLoad]?(點擊了第三個tab之后加載)

從上面的加載過程可以看出炼列,在main()方法之后的啟動中,只要是對頁面的渲染音比,要減少這個階段的耗時需要在viewDidLoad方法中做優(yōu)化唯鸭,減少不必要的邏輯,視圖盡量使用懶加載硅确,使用異步方式加載網(wǎng)絡(luò)數(shù)據(jù)目溉。

三、啟動時間優(yōu)化

蘋果建議在400ms內(nèi)完成pre-main 階段的啟動菱农,App整體的啟動時間不能超過20s缭付,否則系統(tǒng)會被kill掉進程。

由于每個App的體量和類型不一樣循未,對應(yīng)啟動過程中配置的邏輯處理復(fù)雜程度也是皆不相同陷猫,所有沒有一個標準的時間來衡量啟動時間是否達到最優(yōu)。但是可以從用戶體驗上下功夫預(yù)加載占位視圖的妖,數(shù)據(jù)緩存等都可以營造出加載速度提升的感覺绣檬。

下面從實踐的角度分析可優(yōu)化的部分:

pre-main 階段優(yōu)化

1、移除不需要的動態(tài)庫framework

2嫂粟、移除不需要的類娇未、未使用的變量、方法等

對應(yīng)項目中大量的文件星虹,可以使用工具快速掃描整個項目找出未使用的類零抬、變量、或方法宽涌。這里推薦一個開源工具 Fui 能準確的完成此任務(wù)平夜,不足之處在于它處理不了動態(tài)庫或靜態(tài)庫中提供的類,和C++ 的類模板卸亮。

Fui使用方法:

在終端中cd到項目根目錄忽妒,然后執(zhí)行fui find,就可以得到一個列表兼贸,可根據(jù)這個列表在Xcode中手動檢查并刪除無用代碼段直。

3、合并功能類似的類和擴展(Category)

4、+load方法中做的事情可以使用dispatch_once()來代替扶镀,因為main()方法被調(diào)用之前就會加載+load方法呻率,會影響pre-main階段啟動事件。

5京闰、壓縮資源圖片(對要求不高的圖片可做壓縮處理)

main 階段優(yōu)化

1、優(yōu)化application: didFinishLaunchingWithOptions:內(nèi)部邏輯

各種業(yè)務(wù)請求配置更新甩苛,多個配置更新可合并為單個請求蹂楣,部分業(yè)務(wù)的配置延后更新。

對于新版本引導(dǎo)讯蒲、廣告閃屏邏輯痊土,需要重構(gòu)邏輯清晰

數(shù)據(jù)遷移,對太舊的無用的邏輯可以刪除墨林,不需要立即處理的數(shù)據(jù)赁酝,改為后臺加載

2犯祠、優(yōu)化rootViewController加載:在啟動過程中只加載tabbarVc,主Vc即可酌呆,而且主Vc中的ViewDidLoad方法中也只加載需要立即顯示出來的view衡载,其他視圖均使用懶加載,數(shù)據(jù)進行異步加載隙袁。


文章轉(zhuǎn)載:https://www.dazhuanlan.com/2020/01/04/5e1055a4e07fa/?__cf_chl_jschl_tk__=7750f38bebb1f21fdaddcddca0415ee71d31c736-1614321013-0-AWpmiwwC2bq_8PHZ6dbnAI7dbzqLC36vJnCCmhi6ThuE9vMnd3LM67aZyDLR_NJL9OD6mRUWHOQyh3g4j0Pu2gfxG2bqnAUKHjusvzyCt9SgFPr_BvqiVVboKbJT2CnMKE17X9TXh29kBG4pUgxySpMoZiroz9gDZaKkCapAOGs88StJKu4rDYYjwNwCfv5apw7KDW2yUwjsu-8JFscQ3j0KlbepXj_f87G1Cq2LI0JosaCI1xKUmw1csldKhrqcDOmp-hMtRnt6tF_8dQ1ggjBaRUb0qne-6PNV4HeCmgyrGT4o2mjAJDBLu8aaGNuROH0camvmKwRQHg5_L0zQT0I

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末痰娱,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子菩收,更是在濱河造成了極大的恐慌梨睁,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件娜饵,死亡現(xiàn)場離奇詭異坡贺,居然都是意外死亡,警方通過查閱死者的電腦和手機划咐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進店門拴念,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人褐缠,你說我怎么就攤上這事政鼠。” “怎么了队魏?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵公般,是天一觀的道長。 經(jīng)常有香客問我胡桨,道長官帘,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任昧谊,我火速辦了婚禮刽虹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘呢诬。我一直安慰自己涌哲,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布尚镰。 她就那樣靜靜地躺著阀圾,像睡著了一般。 火紅的嫁衣襯著肌膚如雪狗唉。 梳的紋絲不亂的頭發(fā)上初烘,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天,我揣著相機與錄音,去河邊找鬼肾筐。 笑死哆料,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的吗铐。 我是一名探鬼主播剧劝,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼抓歼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起拢锹,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤谣妻,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后卒稳,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蹋半,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年充坑,在試婚紗的時候發(fā)現(xiàn)自己被綠了减江。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡捻爷,死狀恐怖辈灼,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情也榄,我是刑警寧澤巡莹,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站甜紫,受9級特大地震影響降宅,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜囚霸,卻給世界環(huán)境...
    茶點故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一腰根、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧拓型,春花似錦额嘿、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至揣云,卻和暖如春捕儒,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工刘莹, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留阎毅,地道東北人。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓点弯,卻偏偏與公主長得像扇调,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子抢肛,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,500評論 2 359

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