iOS啓動優化之實踐篇

掃一掃關注公衆號,得到更多iOS相關內容bash


這篇文章會給你們介紹一下關於啓動優化,咱們能夠從哪些方面入手,而不會講具體的實現,具體的實現會在後面其它專題的文章中陸續給你們引出來。app

這篇文章所提的啓動都是冷啓動。函數

爲何要進行啓動優化

在進行啓動優化以前,咱們首先要知道爲何要進行啓動優化,相信看了下面這組數據,你就會意識到啓動優化的重要性:性能

  • iOS應用啓動時間一旦超過20s,系統會認爲發生了死循環並殺掉App進程。
  • 互聯網領域八秒定律是指用戶訪問一個網站時,若是等待網頁打開的時間超過8秒,會有超過70%的用戶放棄等待。
  • 若是應用啓動時長超過3秒,會有70%的用戶直接卸載應用。

啓動時間的計算方式

iOS冷啓動過程爲:從用戶點擊App圖標開始到appDelegate didFinishLaunching方法執行完成爲止。這個過程主要分爲兩個階段:測試

  • main()函數以前:即操做系統加載App可執行文件到內存,而後執行一系列的加載、連接等工做,最後執行至App的main()函數。
  • main()函數以後:即從main()開始,到appDelegate的didFinishLaunchingWithOptions方法執行完畢。
啓動時間(T)= main()函數執行以前的時間(T1)+ main()函數執行以後的時間(T2).
複製代碼

如何測量啓動時間

測量main()函數以前的時間

dyld裏有內置的測量系統,能夠經過設置環境變量訪問:優化

測量main()函數以後的時間

這段時間咱們能夠經過插入代碼來測量。網站

  • 先在main()函數裏用變量StartTime記錄當前時間:
CFAbsoluteTime StartTime;

int main(int argc, char * argv[]) {
    StartTime = CFAbsoluteTimeGetCurrent();
    ...
}
複製代碼
  • 在AppDelegate.m文件中用extern聲明全局變量StartTime
extern CFAbsoluteTime StartTime;
複製代碼
  • 在didFinishLaunchingWithOptions裏,獲取一下當前時間,與StartTime的差值便是main()函數以後的運行時間。
double launchTime = (CFAbsoluteTimeGetCurrent() - StartTime);
複製代碼

開始啓動優化

啓動速度要多快

蘋果的經驗法則告訴咱們:400ms是一個不錯的啓動時間。 **注意:**在測量啓動時間時,須要在最慢的支持設備上進行測試。spa

main()函數以前

先回顧下Dyld的加載步驟: 操作系統

接下來咱們從這幾個步驟來分析下有哪些能夠進行啓動優化的點

Load dylibs

平均每一個應用會包含100到400個dylib,可是系統的dylibs很是快。 加載內嵌的dylib很是昂貴。線程

優化方案:依賴的dylib越少越好。

  • 儘可能不使用內嵌的dylib。
  • 合併已有的dylib。
  • 使用dlopen()函數懶加載dylib,不建議用。由於,dlopen()會帶來細微的性能和正確性的問題,實際在以後會帶來更多的工做量。
Rebase & Bind

Rebase因爲有許多I/O操做,會慢一些,而Bind在計算上會昂貴一些。其時間都消耗在修復__DATA段裏的指針上。

優化方案:減小修復指針的數量

  • 減小ObjC類(class)、方法(selector)、分類(category)的數量。
  • 減小C++虛函數的的數量。
  • 使用Swift structs,Swift語言內部作了優化,符號量更少且更內聯。
ObjC

大部分ObjC初始化工做已經在Rebase & Bind階段完成了,這一步dyld會註冊全部聲明過的ObjC類,將分類插入到類的方法列表中,再檢查每一個selector的惟一性。

優化方案:同Rebase & Bind

initializers

這個階段,dyld開始運行程序的初始化函數,調用每一個Objc類和分類的+load方法,調用C/C++ 中的構造器函數(用attribute((constructor))修飾的函數),和建立非基本類型的C++靜態全局變量。

優化方案

  • 少使用+load方法
    • 儘可能把這些事情推遲到+initiailize
    • 將+load方法的加載與執行分離,加載放到main以前執行大概耗時5毫秒,執行放到main以後的一個合適的時機。後面,我會專門寫一篇文章來介紹這個方案。
  • 減小構造器函數個數,在構造器函數裏少作些事情。
  • 減小C++靜態全局變量的個數。

main()函數以後

這一階段要根據具體的業務進行優化,這裏不作過多闡述,後面的文章中也會有相關內容,記住指導原則:在知足業務須要的前提下,didFinishLaunchingWithOptions在主線程裏作的事情越少越好。

相關文章
相關標籤/搜索