iOS關於啓動時間的檢測及優化

啓動時間

啓動時間可謂是用戶對你的App的第一印象,用戶好不容易下載了App,然後饒有興致的開打App,啓動時間過長很可能會讓用戶直接把App打入冷宮。就算用戶非常有耐心,蘋果的watch dog機制也會kill掉啓動時間過長的App,這種情況下給用戶的感覺就是這App怎麼一啓動就卡死然後崩潰了,然後無情卸載。這裏還要說一下,Xcode在debug模式下是沒有開啓watch dog的,所以不要以爲調試時候沒問題就真的沒問題了,一定要在真機上測試一下。

首先我們瞭解一下App的啓動流程
App啓動流程圖
通過實際的調試,我們得到各個函數的調用順序如下:

  1. 啓動頁
  2. main()
  3. UIApplicationMain()
  4. willFinishLaunchingWithOptions()
  5. didFinishLaunchingWithOptions()
  6. loadView()
  7. viewDidLoad()
  8. applicationDidBecomeActive()
    啓動頁是在main()函數調用之前出來的,main()是程序的入口,裏面調用了UIApplicationMain()。當App從didFinishLaunchingWithOptions()返回的時候,實際的UI立刻開始加載,但是在applicationDidBecomeActive()這個回調完成之前,UI即使已經初始化,但仍舊被阻塞着。

總的啓動時間T包括main()調用之前的pre-main timeT1,加上從main()applicationDidBecomeActive()的時間T2。

獲取啓動時間

我們可以通過環境變量的方法來獲取pre-main time。打開Xcode->Product->Scheme->Edit Scheme或者直接command+shift+<(在鍵盤上是逗號,按住shift就是小於號了)。在Edit Scheme中添加DYLD_PRINT_STATISTICS這個環境變量,如果要打印詳細的時間分佈,可以將value設爲1
Edit Scheme
運行項目之後就會在控制檯會打印出每個階段都耗時多少
在這裏插入圖片描述
dylib loading time:加載動態庫
rebase/binding time:修正指針和數據。此外,因爲Objc是一種動態語言,因此需要註冊類名與類相關信息的一張註冊表,對在其他dylib中定義的category,也需要通過rebasing和binding來修正擴展方法的地址來保證selector的唯一性。關於rebase/binding 這塊,有興趣的小夥伴可以看看這篇文章
ObjC setup time:ObjC類初始化
initializer time:其他初始化,如上圖,細分爲其他的幾個部分
libMainThreadChecker:debug時候檢查線程的
瞭解完畢mian()函數之前加載的步驟後,我們可以簡單的分析出影響T1時間的各種因素:

 1. 動態庫加載越多,啓動越慢
 2. ObjC類,方法越多,啓動越慢
 3. ObjC的+load越多,啓動越慢
 4. C的constructor函數越多,啓動越慢
 5. C++靜態對象越多,啓動越慢

我們已經獲取到了main()函數之前的啓動時間T1,至於T2,我們可以使用Xcode自帶工具Instruments裏面的Time Profiler來獲取,也可以在main()的第一句和applicationDidBecomeActive()的最後一句加上獲取時間的代碼CFAbsoluteTimeGetCurrent(),這裏就不細說了。

Time Profiler

工具通過Xcode工具欄中Product->Profile(command+i)可以啓動,(也可以通過Xcode->Open Developer Tool->Instruments)啓動後界面如下:
Instruments
選擇Time Profiler,打開後如圖:
Time Profiler
點擊左上角紅色按鈕運行,勾選左下角Call TreeSeparate ThreadHide System Libraries,等到第一個頁面顯示出來的之後,點擊左上角暫停按鈕,下面就會統計出每個步驟的耗時情況。這個時候我們就可以很容易得到啓動時間T2。

優化啓動時間

針對T1的各個階段分別進行優化處理

1.dylib loading time

  • 核心思想是減少dylibs的引用
  • 合併現有的dylibs
  • 使用靜態庫

2.rebase/binding time

  • 核心思想是在進行動態庫的重定位和綁定(Rebase/binding)過程中減少指針修正;
  • 減少Objective-C類數量,減少分類,減少實例變量和函數(刪除不用的類以及冗餘代碼,再深一點就是減少第三方工具的使用,可以查看源碼,自己實現);
  • 減少C++虛函數;
  • 多使用Swift結構體(推薦使用swift)

3.ObjC setup time
核心思想同上,主要是類的註冊,分類的註冊,唯一Selector。這部分內容基本上在上一階段優化過後就不會太過耗時。

4.initializer time

  • 使用initialize替代load方法
  • 減少使用c/c++的attribute((constructor));推薦使用dispatch_once(),pthread_once(), std:once()等方法
  • 不要在初始化中創建線程
  • 推薦使用swift
針對T2進行優化

我們通過Time Profiler拿到每個步驟的耗時之後,右下角的 Heaviest Trace 可查看比較消耗CPU的代碼,雙擊點擊進去可查看到對應的代碼,進行修改。有些操作可以延後執行,或者異步執行等,這些需要根據自己的業務邏輯在處理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章