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