五分鐘技術趣談 | 淺談Android應用啟動優化方法
啟動速度優化的難易程度與具體的app關系很大,基本隨著用戶量級和業務的增加,啟動優化的難度也隨之增加。因此不同的開發人員由于面對的app不同,對于啟動優化的理解也往往差異很大。本文針對啟動優化工作做一次深入的分析,從啟動優化問題的定義,到問題的細化分解,再到具體優化的步驟和需要使用的工具,來幫助開發者高效的解決啟動性能問題。文章中除了工具部分是針對Android平臺之外,其余部分的思考應該是通用的。
Part 01
問題定義
啟動優化是一個非常普遍的工作,很多開發同學聽到這個詞之后,基本上會下意識的對其進行解釋:”啟動優化就是提升app的啟動速度“。這個理解是最直接最樸素的,但是只是涵蓋了啟動優化的部分內容。
整體啟動優化工作可以概括為:在系統資源一定的情況下,優化應用的啟動流程,使應用啟動的關鍵路徑能夠最大化利用系統資源,并長期維持在穩定的范圍內。
任何問題都需要首先劃定邊界,來幫助我們降低復雜度并確定方案實施的范圍。對于啟動優化來說,首先要做的就是定義要優化的app啟動的起始點和結束點是哪里,這里針對不同的app,對于起始和結束的位置定義可能會有不同。通常我們建議從用戶體驗的角度出發,來做適合各自情況的定義。
Part 02
重中之重-數據
數據是我們做優化工作的重中之重,它指導優化工作的方向,應該以從數據中發現問題,并最終通過數據來驗證問題的解決的原則進行優化工作。
所以在實施優化策略之前,所要做的第一件事情就是盡可能詳細的收集啟動階段的數據,當前的啟動時間是多少、啟動各個子階段耗時如何、各種異步任務耗時情況、啟動階段CPU等系統資源使用情況、進程及線程情況等等,這些數據都是需要收集的,而且需要從不同的維度來對數據進行分析。
數據梳理和收集的工作,一方面可以幫助我們梳理目前的指標,另一方面梳理數據的過程,可以從代碼層面加深開發者對系統整個啟動過程的了解,幫助開發者抓住系統啟動的主脈絡,將其了然于胸,建立數據項與代碼邏輯的關聯,當數據某一項發生波動時,開發者才能夠直接定位到可能出問題的代碼模塊。
Part 03
優化思路
單看啟動速度優化工作我們可以從兩個方向著手,業務流程優化和系統資源的使用優化。
3.1 業務流程優化
業務流程優化,就是優化啟動階段涉及到的業務流程。這里說的業務流程優化有兩方面的含義:
- 非必要的任務,即不影響app達到可用狀態的任務,這種任務我們可以盡量去延遲初始化。
- 需要保證關鍵啟動路徑上面子任務的有效銜接,不存在某一任務執行時間過長,導致其他任務等待的情況。
第1點應該比較好理解,我們來解釋下第2點:
整體啟動過程,我們需要找出啟動流程的關鍵路徑,而關鍵路徑往往是由多個不同流程組成。關鍵路徑上面的任務、流程如果有等待的情況,那么就是我們需要優化的地方。
比如,一個啟動時有閃屏廣告的app,啟動時需要拉取廣告數據,并在廣告展示結束后才進入主界面。那么廣告數據的獲取和獲取后的展示,就可以理解為啟動階段的兩個關聯的子任務,如果在主線程進入到廣告展示階段后,廣告數據依然沒有返回,這里就會存在等待廣告數據返回的時間,也就是子線程(任務)之間沒有有效的銜接。
業務流程優化這部分大家最關注的就是各種啟動任務的管理,很多分享的文章都介紹了啟動任務異步管理框架的設計。這里不再重復這部分內容,我們補充下與任務管理相關的其他方面的工作:
- 進程的管理,以及不同進程的啟動任務管理。在Android系統中,多數大型app都是多進程app,那么主進程外的各個進程的初始化時機就應該成為啟動優化關注的點,這個在系統資源優化中也會提到。而且任務框架需要能夠支持對于不同的進程配置不同的啟動任務,同時同一個啟動任務在不同進程中支持不同的執行方式(同步或異步)。
- 啟動框架應該具有任務執行時間、任務等待時間、整體任務吞吐情況的統計功能,甚至可以根據數據調整本身的并發線程數量。
- 將啟動過程劃分為不同的階段,任務也歸為不同的階段執行。
3.2 系統資源優化
業務流程優化與系統資源使用優化并不是分割開來的,業務流程優化本來就是為了保證我們最有效的利用系統資源,而系統資源使用優化是從另一個角度來讓我們審視當前的業務流程是否合理。
系統資源很多數據指標不好衡量,比如如何衡量啟動階段cpu的利用率,如何衡量線程的執行效率等。所以這部分工作線上數據收集比較困難,開發者應該主要著手完善開發工具,通過工具來發現問題。
系統資源優化主要看以下方面的指標:
- CPU使用是否合理,關注線程鎖競爭問題、主要線程獲取cpu時間片情況、主要線程執行狀態(runnable、running、sleep)、主進程獲取cpu時間是否不足、線程是否過度競爭等。這里面會涉及到對鎖競爭的發現和處理、對線程優先級的處理、對進程啟動時機的把控、IO是否有阻塞線程等優化方向。
- IO使用是否合理(包括網絡和本地IO),關注是否存在頻繁IO,是否有啟動階段不必要的IO操作,IO是否引起主要線程阻塞,是否有大文件讀寫等。
- 線程情況,包括線程池使用是否合理,線程數量是否過多,線程間任務協作是否存在延遲等。
- 內存情況,主要觀察是否有過多的gc問題,啟動階段heap內存是否占用過多等。
以上兩個方向的工作,基本上涵蓋了啟動速度指標優化的絕大部分工作內容。值得指出的是,上面的工作并不是說將所有的方面都優化一遍就結束了,而是需要經常回頭看,因為隨著優化工作的進行,啟動的狀況是會發生變化的(比如之前沒有沖突的鎖,可能開始發生沖突)。
另一個值得注意的點就是,針對每一個具體的優化策略,開發者應該在本地實驗環境下進行充分的測試,例如針對高中低端機型、不同網絡類型等來評估優化策略所能帶來的收益。由于線上機型各異、網絡情況也比較復雜,很多時候策略上線后并不能達到預期中的效果,所以每一個優化最好通過線上AB實驗來對比觀測數據。
3.3 性能持續保障——與熵的對抗
啟動優化很重要的另一個方面就是如何持續的保障當前優化的效果不隨著功能的迭代而惡化。我們對于流程和資源使用的優化,本質上是使代碼在執行過程中保證一定的有序性,這種有序性保證了啟動關鍵鏈路對資源的使用率。 但是隨著代碼的增加,app業務越來越多,這種有序性是非常容易被打破的。根據熵增定律,如果我們不采取措施,那么系統肯定會向著混亂的方向發展,也就是說無論你之前花了多大的力氣優化,系統性能總會逐步惡化,不處理解決這種惡化趨勢那么就會前功盡棄。
那么如何與熵增進行對抗?在我們的日常生活中,一條馬路不定時的會有路段處于修整的狀態,這種修整就是對抗熵增的方法,也是我們工程上要采取的策略——發現并解決問題。但是在代碼中,問題的發現卻不能夠那么直觀,數據可以告訴我們性能發生了惡化,但是具體惡化點在哪里,往往需要我們花費很大的力氣去定位。所以在持續保障方面,我們要做的就是如何盡早的發現問題和盡快的定位解決問題。
持續保障機制需要建立一套實驗室性能測試環境:
- 能夠建立性能基線,在日常開發中能夠及時發現代碼合入引發的性能問題,直接定位到引起問題的MR,有效減少定位問題的復雜度;
- 在灰度階段持續監控線上性能數據,在上線前checkList把控版本性能影響;
- 線上針對性能建立數據指標&報警機制,監控線上功能變更引起的性能問題;
- 階段化數據指標,直觀反映變更對性能的影響區間,縮小問題定位范圍。
總體來說,針對啟動性能優化,我們要建立下圖所示的工作流程,來保證優化工作的效率、有效性和持續的效果:
圖片
上面我們主要列出了啟動優化工作主體的思考方向,并沒有涵蓋這些方向下面所有的優化點。值得指出的是我們在制定優化策略時,需要根據各自app的情況因地制宜, 根據自身的情況來發現問題點,并確定優化策略的優先級,哪些策略要優先上,哪些策略沒有必要實施(考慮ROI); 同時需要事先評估各個策略的收益,而不是將所有的策略列出來一股腦兒的挨個優化。
Part 04
優化工具(Android)
工欲善其事必先利其器,在優化工作中我們通常會遇到類似以下問題:
- 啟動流程鏈路長、任務多、代碼復雜,需要花費很大力氣理清整體啟動鏈路;
- 很難度量啟動過程中系統資源情況,例如cpu使用情況、多線程鎖競爭、內存、IO等;
- 無法準確定位啟動過程中的高耗時函數或者瓶頸流程;
- 在優化策略上線前,無法準確衡量實施優化策略后的具體收益;
- ......
針對線程優化、IO優化等專項,有類似Matrix這種工具,可以比較好的幫助我們發現問題。我這里想重點介紹下Android提供的Perfetto工具,因為它可以幫助我們很好地了解系統的整個啟動過程,以及各種系統資源的使用情況。并且基于Perfetto提供的api,我們可以開發出強大的自動分析工具,幫助我們在發現問題、定位問題、優化策略效果評估等方面產出自動化的工具。
4.1 Perfetto功能介紹
首先Perfetto提供的可視化工具,可以幫助我們從各種不同的角度來分析app運行的一段時間內的情況,簡單舉幾個例子:
查看一段時間內,各個進程占用CPU時間情況:
圖片
查看一段時間內,不同進程內線程占用CPU情況:
圖片
顯示一段時間內線程執行狀態信息:
圖片
除了上面例子外,可視化工具還可以分析多線程鎖競爭問題、文件IO問題、Heap內存變化等情況,對于日常的優化工作有很大幫助。上面只是舉例子,很多功能還需要實際使用去進一步體驗。
Perfetto真正強大的地方并不是提供的可視化工具,而是它提供了一套對數據進行收集和分析的能力:
- 將收集的系統數據做了組織整理,并將數據以一些可以支持SQL查詢的數據表暴露給開發者,進而支持我們對數據進行自定義的分析SQL數據表;
- 提供了Tracing SDK, 可以讓app開發者向perfetto-trace文件中添加自定義的事件,在分析時使用TracingSDK;
- 提供了Python API,使開發者可以基于python對trace文件進行分析trace-analysis。
實際上Perfetto提供給我們一套可以實現自動化分析app性能、發現性能問題的工具的能力,并且如果將這種自動化能力與我們日常的開發流水線結合,對于性能問題的盡早發現、防劣化等能力建設都會有很大的幫助。
隨著應用版本的迭代,應用啟動數據會隨著發生變化,因此啟動優化工作也需要長期迭代,做到對啟動體驗的持續保障。本文主要針對啟動優化工作的思路、實施方法和工具等方面進行了總結,在實際工作中不同用戶規模的應用所面臨的優化問題也各不相同,希望這里的總結能夠對大家有所啟發。