App啓動速度優化與監控

最近在作一款陌生人社交的軟件,市場上這類軟件都是大同小異。爲了能讓產品比競品更具競爭力,作爲開發者,除了完成來自產品經理需求外,咱們能作的還有這些:markdown

  • 崩潰率優化
  • 交互的優化
  • 動畫的優化

我把App啓動速度的優化歸結在交互優化中app

通常狀況下,App的啓動分爲冷啓動和熱啓動異步

  • 冷啓動 app啓動前,它的進程不在系統裏,須要系統新建立一個進程分配給他啓動的狀況,即App從被殺死的狀況下啓動
  • 熱啓動

app在冷啓動後將程序退到後臺,在app進程還在系統裏的狀況下,用戶重 新啓動進入app的過程,即app從被掛起的狀況下啓動,這個過程作的事情很是少函數

這篇文章主要探討app冷啓動的優化 用戶能感知到的啓動慢,其實都發生在主線程上,而主線程慢的緣由有不少,好比在主線程上執行了大文件讀寫操做、在渲染週期執行了大量計算等。可是,有時候你會發現即便你把首屏顯示以前的這些主線程的耗時問題都解決了,仍是比競品啓動得慢。工具

通常而言,App的啓動時間,指的是從用戶點擊App開始,到用戶看到第一個界面之間的時間,總結來講,App的啓動主要包括三個階段:大數據

  1. main()函數執行前
  2. main()函數執行後
  3. 首屏渲染完成後

main()函數執行前

main()函數執行前,系統主要會作下面幾件事:優化

  • 加載可執行文件(App的.o文件的集合)
  • 加載動態連接庫,進行rebase指針調整和bind符號綁定
  • objc 運行時的初始處理,包括objc相關類的註冊、category註冊、selector惟一性檢查等
  • 初始化,包括了執行+load()方法、attribute((constructor))修飾的函數的調用、建立C++靜態全局變量

響應的,在這個階段對於啓動速度優化來講,能夠作的事情包括:動畫

  • 減小動態庫加載,每一個庫自己都有依賴關係,蘋果官方建議使用更少的動態庫,而且建議在使用動態庫的數量較多時,儘可能將多個動態庫進行合併。數量上,蘋果公司最多能夠支持6個非系統動態庫合併爲1個
  • 減小加載啓動後不會去使用的類或者方法
  • +load()方法裏的內容能夠放到首屏渲染完成後再執行,或使用+initialize方法替換掉。由於,在一個+load()方法裏,運行運行時方法替換操做會帶來4毫秒的消耗,不要小看這4毫秒,聚沙成塔,執行+load()方法對啓動速度的影響會愈來愈大
  • 控制C++全局變量的數量

main()函數執行後

main()函數執行後的階段,指的是從main() 函數執行開始,到 appDelegate的(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {}方法裏首屏渲染相關方法執行完成 首頁的業務代碼都是要在這個階段,也就是首屏渲染前執行的,主要包括了:spa

  • 首屏初始化所需配置文件的讀寫操做
  • 首屏列表大數據的讀取
  • 首屏渲染的大量計算等

不少時候,咱們會把各類初始化工做都放到這個階段執行(如各種sdk初始化),致使渲染完成置後。更加優化的開發方式,應該是從功能上梳理出哪些是首屏渲染必要的初始化功能,哪些是App啓動必要的初始化功能,而哪些是隻須要在對應功能開始使用時才須要初始化的。梳理完以後,將這些初始化功能分別放到合適的階段進行。線程

首屏顯示完成後

首屏渲染完成後的這個階段,主要完成的是,非首屏其它業務服務模塊的初始化、監聽的註冊、配置文件的讀取等。從函數上來看,這個階段指的就是截止到(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {}方法做用域內執行首屏渲染以後的全部執行方法。簡單說的話,這個階段就是從渲染完成時,到(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {}方法做用域結束時結束。

這個階段用戶已經可以看到App的首頁信息了,因此優化的優先級排在最後。可是,那些會卡住主線程的方法仍是須要最優先處理的,否則仍是會影響到用戶後面的交互操做。

明白了App啓動階段須要完成的工做後,咱們就能夠有的放矢的進行啓動速度的優化了。這些優化,包括了功能級別和方法級別的優化

功能級別的啓動優化

功能級別的啓動優化,就是要從main()函數執行後這個階段入手

優化的思路是:main()函數開始執行後到首屏渲染完成前只處理首屏相關的業務,其餘非首屏業務的初始化、監聽註冊、配置文件讀取等都放到首屏渲染完成後去作

方法級別的啓動優化

通過功能級別的啓動優化,也就是將首屏業務所需的功能滯後之後,當用戶點擊App到看到首屏的時間將會很大程度的縮減,也就達到了優化App啓動速度的目的。

在這以後,咱們須要進一步作的,是堅持首屏渲染完成前主線程上有哪些耗時方法,將不必的耗時方法滯後或者異步執行。一般狀況下,耗時較長的方法主要發生在計算大量數據的狀況下,具體的表現就是加載、編輯、儲存圖片和文件等資源

App啓動速度的監控

  • 定時抓取主線程上的方法調用堆棧,計算一段時間裏各個方法的耗時。Xcode工具裏的Time Profile 採用的就是這種方式
  • objc_msgSend 方法進行hook來掌握全部方法的執行耗時

hook方法的意思是,在原方法開始執行時換成其餘你指定的方法,或者再原有方法執行先後執行你指定的方法,來達到掌握和改變指定方法的目的。

hook objc_msgSend這種方式的優勢是很是精確,而缺點是隻能針對Objective-C方法。對於c方法和block,可使用libffi 的ffi_call來達成hook。缺點就是編寫維護相關工具門檻高

綜上,若是對於檢查結果精準度要求高的話,推薦使用hool objc_msgSend方式來檢查啓動方法的執行耗時

相關文章
相關標籤/搜索