背景
冷啟動時長是App性能的重要指標(biāo)榆骚,作為用戶體驗的第一道“門”晶框,直接決定著用戶對App的第一印象吉执。 招聘客戶端App都對啟動時長或多或少都進(jìn)行過一些優(yōu)化挺益,但相對于主流App啟動時長差了不少涕蚤,仍然有較大的優(yōu)化空間宪卿。
方向
本次啟動專項分析從兩個方向重點進(jìn)行分析:
一、美團(tuán)啟動分析(美團(tuán)App啟動為什么快万栅?)
二佑钾、招才貓啟動分析(我們App啟動為什么比美團(tuán)慢?)
三烦粒、后續(xù)規(guī)劃
定義
冷啟動定義
雖然冷iOS啟動有:開機(jī)啟動App(完全冷啟動)和短時間內(nèi)再次啟動App(溫啟動)兩種休溶,但對于啟動流程和將要做的啟動優(yōu)化來說并無區(qū)別代赁。一般而言,可以把iOS冷啟動的過程定義為:從用戶點擊App圖標(biāo)開始到第一個頁面展示為止兽掰。
啟動過程階段定義
啟動過程可以分為三個階段進(jìn)行分析:
T1:main函數(shù)之前芭碍,系統(tǒng)會進(jìn)行加載動態(tài)庫、注冊O(shè)bjc類等系統(tǒng)操作
T2:main函數(shù)到didFinishLaunching方法執(zhí)行完成期間會進(jìn)行SDK初始化等操作
T3:didFinishLaunching執(zhí)行完成到首頁面展示期間會進(jìn)行頁面的創(chuàng)建和渲染工作
美團(tuán)App啟動分析
一孽尽、如何統(tǒng)計第三方App
關(guān)于如何統(tǒng)計競品或者主流App的啟動耗時情況窖壕,市面上包含知乎團(tuán)隊采用的方案是進(jìn)行屏幕錄制+腳本,分析視頻圖像相似度的關(guān)鍵時間節(jié)點杉女。此方案弊端較多瞻讽,這里以逆向分析的方向提供兩種統(tǒng)計方案:
- Theos+Tweak 越獄開發(fā)工具包,可注入代碼到正版App中
- Frida+Monkey 砸殼重裝熏挎,注入代碼重新安裝App且可進(jìn)行- Debug調(diào)試
此次分析采用的是Frida+Monkey的方式速勇,最終都會將注入代碼以.dylib的方式注入到App中, 新注入的dylib庫會增加一定的耗時坎拐,需要忽略掉烦磁。
libmeituanDylib.p : 34.00 milliseconds (1.6%) // 忽略
imeituan : 107.84 milliseconds (5.0%)
二、準(zhǔn)備注入的代碼
將App啟動過程中T2哼勇、T3階段關(guān)鍵時間節(jié)點方法進(jìn)行hook:
- 1都伪、利用sysctl函數(shù)獲取進(jìn)程創(chuàng)建時間
- 2、利用切面Hook猴蹂,對系統(tǒng)方法 didFinishLaunchingWithOptions 的開始和結(jié)束調(diào)用進(jìn)行打點
- 3院溺、利用MoneyDev中的Logos語法,找到首頁的Controller磅轻,對viewDidAppear方法進(jìn)行hook打點珍逸。 (ps:如果直接對UIViewController的viewDidAppear進(jìn)行hook,拿到的時長一般都是TabBarVC聋溜、NavigationVC顯示的時長)
打點:
%hook MBCContainerViewController
- (void)viewDidAppear:(BOOL)animated {
%orig;
// 打點
}
%end
三谆膳、美團(tuán)App啟動階段時長分析
T1階段耗時分析
添加Xcode配置 DYLD_PRINT_STATISTICS_DETAILS 得出 pre-main 階段耗時以美團(tuán)為標(biāo)準(zhǔn),招才貓的pre-main耗時比美團(tuán)多350ms:
- dylib loading time: 動態(tài)庫加載時長撮躁,經(jīng)過分析美團(tuán)的動態(tài)庫數(shù)量為148個漱病,招才貓為73個,耗時相差85ms把曼,轉(zhuǎn)換成真實啟動耗時影響較小杨帽,且系統(tǒng)已經(jīng)對動態(tài)庫的加載做過優(yōu)化,這部分耗時屬于正常嗤军。
- rebase/binding注盈、Objc setup time:這部分耗時與項目中包含的類、方法數(shù)量形成正比叙赚,從美團(tuán)250M老客,招才貓120M的包大小估算僚饭,這階段耗時屬于正常。
- initializer time: 此階段會調(diào)用每個Objc和分類的+load方法胧砰,調(diào)用C/C++的構(gòu)造函數(shù)等操作鳍鸵,從分析結(jié)果來看,招才貓在此階段耗時明顯過多尉间,需重點排查偿乖,著重排查+load方法。
T2階段耗時分析
T2階段為 -application:didFinishLaunchingWithOptions: 中SDK初始化乌妒、任務(wù)創(chuàng)建等App部分功能初始化相關(guān)工作汹想,對美團(tuán)的MTAppdelegate類中的didFinishLaunching進(jìn)行逆向分析。
中間省去N多靜態(tài)分析和動態(tài)調(diào)試撤蚊。。损话。
最終得到美團(tuán)App的啟動任務(wù)管理列表:didFinishLaunchingWithOptions 階段
- 可以看出侦啸,美團(tuán)App在didFinishLaunchingWithOptions中執(zhí)行的主線程Task是相當(dāng)少的,而且很大一部分是屬于基礎(chǔ)類丧枪、基礎(chǔ)數(shù)據(jù)配置的構(gòu)造光涂,這部分耗時是非常少的,必要的幾個任務(wù)也放在了子線程處理拧烦,以最優(yōu)的方式使-didFinishLaunchingWithOptions快速的執(zhí)行完成忘闻,直接去展示頁面,可以說美團(tuán)在這方面是做得很好恋博。
- 可以發(fā)現(xiàn)這階段中首先有個任務(wù)叫 RunAllLoadFunctions齐佳,可以大膽猜測一下,美團(tuán)是否把本應(yīng)該在main()函數(shù)之前在+load方法中需要做的事情债沮,放在了這個Task中炼吴,以減少+load的數(shù)量。
LaunchForeground 階段
大部分App應(yīng)該都沒有這個階段的一些操作處理疫衩,美團(tuán)也只是在這里進(jìn)行了一些狀態(tài)操作硅蹦,耗時可以忽略的。
viewDidAppear 階段
美團(tuán)將大量(42個)的任務(wù)放在了TabBarController顯示完成之后執(zhí)行闷煤,其中包含了Pay童芹、IM、Spotlight鲤拿、Location假褪、Push、CrashReporter等核心且耗時較大的任務(wù)皆愉。但即使放在了TabBar顯示之后嗜价,也對耗時大的任務(wù)放在了子線程中艇抠,以保證首頁在剛展示后可以流暢的滑動、點擊久锥,不受這些任務(wù)的影響家淤。
notifyT3Completed 階段
根據(jù)這個階段獲取到的堆棧信息,可以猜測分析出應(yīng)該是美團(tuán)App在頁面渲染完成之后做的一些任務(wù)操作瑟由,這些任務(wù)不會影響到App的啟動絮重,所以可以根據(jù)項目需要決定有可借鑒的東西。
美團(tuán)任務(wù)管理方案:
美團(tuán)除了將任務(wù)劃分做很好之外歹苦,任務(wù)的管理中心也做得很好青伤,美團(tuán)的任務(wù)管理核心可以分為三大部分:
RegisterCenter:對Task進(jìn)行注冊、劃分殴瘦、創(chuàng)建狠角、獲取等等。
TaskRunner:運行啟動階段流程中的任務(wù)蚪腋。
StartTask:任務(wù)者丰歌,存儲任務(wù)的信息,監(jiān)控任務(wù)的執(zhí)行狀態(tài)和耗時等屉凯。
美團(tuán)將每個業(yè)務(wù)線的任務(wù)通過attribute 方式 Chain 到了mach-o中(未驗證立帖,也可能是其他方式),將任務(wù)與模塊悠砚、業(yè)務(wù)線之間直接進(jìn)行了解耦晓勇,在啟動過程中獲取每個階段中任務(wù)的函數(shù)指針進(jìn)行執(zhí)行。
美團(tuán)對每個Task做了很多處理灌旧,可以對每個業(yè)務(wù)線的任務(wù)耗時進(jìn)行監(jiān)控绑咱。對于在didFinishLaunching內(nèi)任務(wù)比較重或需要進(jìn)行任務(wù)解耦的App,美團(tuán)的方案是一個不錯的參考节榜。
簡約模仿的任務(wù)管理流程圖:
T3階段耗時分析
T3階段涉及東西較多羡玛,簡單對這階段進(jìn)行一個分析。
1宗苍、從上面內(nèi)容知道美團(tuán)的T3階段是到 MTGroupTabbarController的viewDidAppear方法執(zhí)行為止稼稿,對此方法添加斷點可以看見美團(tuán)的啟動首屏。 通過控制臺log輸出及其他信息讳窟,基本上可以確定首屏上半部分的元素內(nèi)容是暫時靜態(tài)的让歼,在未拉取最新內(nèi)容之前有可展示的區(qū)域,不會發(fā)生內(nèi)容白屏的假啟動現(xiàn)象丽啡。
整體耗時對比分析:
以美團(tuán)為標(biāo)準(zhǔn)辈挂,我們對比一下招才貓和美團(tuán)的溫啟動耗時:
T1階段:上面已經(jīng)對T1階段進(jìn)行了分析衬横,著重排查+load方法造成的影響,從真實的統(tǒng)計時長看终蒂,在T1階段招才貓比美團(tuán)App多耗時了257ms蜂林,從兩個App的體量分析,招才貓App的T1階段耗時在180ms以內(nèi)才屬于正常范圍拇泣。
T2階段:雖然招才貓之前已經(jīng)將非必要的SDK初始化或其他任務(wù)進(jìn)行了管理噪叙,減少或延后到了啟動完成后去執(zhí)行,但以美團(tuán)標(biāo)準(zhǔn)看來霉翔,需要再次對必須在啟動時完成初始化的SDK睁蕾、任務(wù)進(jìn)行梳理,是否仍有延后的可能或在線程中進(jìn)行處理早龟。
T3階段:美團(tuán)和招才貓在此階段耗時相差并不大惫霸,但從觀感上來看,體驗卻相差明顯葱弟。主要原因是美團(tuán)首屏頁可以直接看見一些靜態(tài)展示區(qū)域,而招才貓無論是消息頁面還是附近求職者猜丹,目前都無法在第一時間提供頁面元素芝加, 導(dǎo)致從觀感上認(rèn)為仍然處于啟動階段。
啟動通用優(yōu)化方案
iOS 啟動優(yōu)化市面上有大量的文章射窒、優(yōu)化方案藏杖, 但大家都會發(fā)現(xiàn)為什么自己App在優(yōu)化后,仍然與美團(tuán)等主流App存在較大的差距脉顿。
分析完美團(tuán)的啟動過程蝌麸,我們基本上能了解到美團(tuán)大部分所做的啟動優(yōu)化工作也是大家所熟知的一些方案,但也能得到一些更為重要的信息:
標(biāo)準(zhǔn):針對于每個App的啟動優(yōu)化艾疟,我們需要優(yōu)化到什么程度来吩,在每個階段的耗時應(yīng)該處于什么樣的一個水平,我們有了一個比較清晰的標(biāo)準(zhǔn)去做對比衡量蔽莱。
監(jiān)控:美團(tuán)對自己的每一個啟動任務(wù)都做了一系列的粒度拆分和監(jiān)控弟疆,在對持續(xù)的版本迭代所造成的增量影響和保持良好的啟動時長能有一個更好的管控機(jī)制。
感悟:如果要做到極致的啟動速度盗冷,就需要對Icon點擊到頁面展示的整個通道怠苔,就如同在一個新的App上去重新鋪好這條路,去過濾不必要或可以優(yōu)化的點仪糖。
技術(shù):美團(tuán)可能將+load方法所做的事情放在了main()函數(shù)之后柑司,是否可提高啟動速度迫肖?(待確認(rèn))
招才貓App啟動分析
以美團(tuán)為標(biāo)準(zhǔn),以招才貓為例攒驰,對App的溫啟動時長進(jìn)行分析蟆湖。
一、招才貓分析匯總
主要分析方式:工具分析讼育、階段/任務(wù)打點帐姻、通道重鋪、代碼查看奶段、三方庫逆向分析
招才貓啟動過程分析發(fā)現(xiàn)的部分問題:
饥瓷。
。
痹籍。
省略