iOS 啟動時間優化 —— 相關#
背景#
iOS 的啟動時間優化有很多相關的文章,本來不打算寫,但是總歸是自己整理一遍印象更深刻。這裡打算從原理 - 實踐 - 面試相關三個方面來入手。首先要理解 APP 啟動的原理,啟動做了什麼?然後針對啟動過程中的事件哪些是開發可以進行優化的,去實踐?最後則是,面試相關,與啟動優化相關的面試有很多,筆者打算列舉一下,分別涉及到啟動的哪些問題。
啟動原理#
啟動分為冷啟動和熱啟動。冷啟動指的是 APP 進程被殺掉後,從零打開;熱啟動指的是,APP 進入後臺,再切換到前臺喚起到過程。這裡通常說的啟動優化,指的是冷啟動優化。(Ps: 這裡某些版本會出現,剛殺掉的 APP,立即再次打開,會直接閃退的問題,是系統的 Bug)。
冷啟動的過程分為main函數之前(pre-main)
和main函數之後
兩個階段。
pre-main 階段#
就如很多文章說的:
pre-main 階段的過程分為dylibs loading
——> rebase/binding
——> ObjC setup
——> initializer
四個部分。每個部分吧啦吧啦... 但每次問到這個時候,死記硬背出來真的累人😂。
為什麼會感覺困難呢?是因為不知道這四個步驟哪裡來的,所以只能背,筆者記憶不好,終歸是 “不算年輕了”。
所以除了死記硬背,還能怎麼辦呢?去實踐,然後理解,做過了的事情才印象深刻。
所以來看,如何實踐 & 理解:
先打開 Xcode 的 Scheme,然後在 Run 的選項下,選中Environment Variables
,添加 Name 為DYLD_PRINT_STATISTICS
,Value 為1
。如下:
然後運行一次,會發現控制台中打印出了類似如下的信息:
Total pre-main time: 599.52 milliseconds (100.0%)
dylib loading time: 101.25 milliseconds (16.8%)
rebase/binding time: 55.26 milliseconds (9.2%)
ObjC setup time: 189.95 milliseconds (31.6%)
initializer time: 253.04 milliseconds (42.2%)
slowest intializers :
libSystem.B.dylib : 6.65 milliseconds (1.1%)
libMainThreadChecker.dylib : 59.84 milliseconds (9.9%)
xxxTest : 313.12 milliseconds (52.2%)
這裡面的信息仔細對比:其中Total pre-main time
指的是pre-main
的總時間;
Total pre-main time
≈ dylib loading time
+ rebase/binding time
+ ObjC setup time
+ initializer time
;
slowest intializers
中的libMainThreadChecker
,是因為 Scheme 中的Main Thread Checker
打開了,關閉即可,如下的地方勾選去除即可。
所以pre-main
階段發生了什麼?就是發生了dylib loading
、rebase/binding
、ObjC setup time
、initializer time
。這樣就知道了這 4 個步驟的來歷,接下來再看看這幾個步驟都是做什麼的?
翻譯如下:
Total pre-main time
指的是pre-main
的總時間- 加載所有依賴的動態庫;
- 修正
DATA
中的指針偏差; - 初始化所有對象。
dylib loading time
:- 加載 app 依賴的庫
- 加載庫依賴的庫
rebase/binding time
:- rebasing: 調整鏡像的指針
- binding: 設置指針到外部鏡像
ObjC setup time
:- 註冊 objc 類 (class registration);
- Category 方法插入;
- 保證每個 Selector 唯一;
initializer time
:- C++ 靜態對象初始化
- objc 的
+load
方法加載 - 執行
main()
main 函數之後階段#
main 函數之後的優化,也要多注意,大家都知道application:didFinishLaunchingWithOptions:
是啟動時初始化的方法,那這裡應該做些什麼?
首先問大家一個問題
啟動優化實踐#
application:didFinishLaunchingWithOptions:
中return YES
之前寫一個 sleep (10);所以只要這個方法不返回,界面就會顯示LaunchScreen
,即使已經初始化了首頁設置了 rootVC 也不會顯示。
面試相關#
+initialize、+init、+load 什麼時候調用、調用順序?
+initialize、+load 的區別?
+load 的加載是在 main 函數之前?還是之後?
參考#
Reducing Your App’s Launch Time
optimizing_app_startup_time
iOS 深思篇 | 啟動時間的度量和優化