概要
應(yīng)用運(yùn)行時(shí)的卡頓問(wèn)題非常影響用戶體驗(yàn)荠列,嚴(yán)重降低產(chǎn)品表現(xiàn)力,本文將介紹應(yīng)用卡頓原因以及分析方法等等载城。
卡頓問(wèn)題可分為兩類肌似,應(yīng)用卡頓和系統(tǒng)卡頓,本文針對(duì)系統(tǒng)正常時(shí)應(yīng)用卡頓場(chǎng)景诉瓦。
黃油工程
Android系統(tǒng)每隔16ms發(fā)出VSYNC信號(hào)川队,觸發(fā)對(duì)UI進(jìn)行渲染,如果每次渲染都成功睬澡,這樣就能夠達(dá)到流暢的畫面所需要的60fps固额,為了能夠?qū)崿F(xiàn)60fps,這意味著程序的大多數(shù)操作都必須在16ms內(nèi)完成煞聪。
如上圖斗躏,第1幀在顯示時(shí),GPU并沒(méi)有準(zhǔn)備好第2幀數(shù)據(jù)昔脯,導(dǎo)致第1幀數(shù)據(jù)連續(xù)顯示兩次啄糙,導(dǎo)致不流暢笛臣、卡頓。應(yīng)用需要減輕UI線程負(fù)擔(dān)隧饼,將耗時(shí)工作放入工作線程中沈堡,同時(shí)精簡(jiǎn)繪制工作,保證16ms內(nèi)可以完成一幀繪制燕雁。
圖層疊加
Android通過(guò)圖層疊加完成繪制诞丽。
左側(cè)的對(duì)象是生成圖形緩沖區(qū)的渲染器,如主屏幕拐格、狀態(tài)欄和系統(tǒng)界面僧免。SurfaceFlinger 是合成器,屏幕負(fù)責(zé)顯示合成界面禁荒。
應(yīng)用界面層級(jí)應(yīng)該盡量精簡(jiǎn)猬膨,同時(shí)減少過(guò)度繪制問(wèn)題,減輕系統(tǒng)壓力呛伴。
卡頓原因
應(yīng)用卡頓常見(jiàn)的原因勃痴,UI線程負(fù)荷過(guò)重,繪制代碼不當(dāng)?shù)热瓤怠O到y(tǒng)卡頓或資源緊張也有可能導(dǎo)致應(yīng)用卡頓沛申,gc過(guò)多也能導(dǎo)致卡頓。此外姐军,過(guò)度繪制铁材,界面層級(jí)過(guò)多也會(huì)導(dǎo)致繪制效率下降。
在某些GPU性能較差的機(jī)器上奕锌,alpha動(dòng)畫效率低下著觉,也會(huì)導(dǎo)致卡頓。
分析方法
遇到卡頓問(wèn)題惊暴,從現(xiàn)象入手饼丘,排除系統(tǒng)卡頓原因,接下來(lái)可通過(guò)log分析辽话、工具定位解決卡頓問(wèn)題肄鸽。常用工具為traceview,systrace等油啤。
Traceview典徘,針對(duì)單一應(yīng)用,統(tǒng)計(jì)具體一段時(shí)間內(nèi)方法執(zhí)行時(shí)間益咬、次數(shù)等信息逮诲。
Systrace,記錄整機(jī)運(yùn)行情況,包括cpu使用情況汛骂,vsync信號(hào)罕模,gc信息等等,它也能記錄部分方法的執(zhí)行情況帘瞭,時(shí)間等淑掌。
Log分析,重點(diǎn)跟蹤gc情況蝶念,具體業(yè)務(wù)邏輯流程等抛腕。
Traceview
Traceview有兩種使用方式,既可使用DDMS采集數(shù)據(jù)媒殉,也可使用Debug類采集數(shù)據(jù)担敌。使用DDMS采集數(shù)據(jù)的步驟如下:
- 在應(yīng)用的AndroidManifest.xml添加 android:debuggable="true",打開(kāi)debug屬性
- 打開(kāi)DDMS面板廷蓉,選中調(diào)試的應(yīng)用
- 點(diǎn)擊 Start Method Profiling 按鈕
- 操作機(jī)器全封,執(zhí)行對(duì)應(yīng)需要性能分析的過(guò)程
- 點(diǎn)擊 Stop Method Profiling 按鈕
抓取數(shù)據(jù)完成后會(huì)自動(dòng)跳轉(zhuǎn)到traceview界面。
除了使用DDMS采集數(shù)據(jù)桃犬,也可以使用Debug類采集數(shù)據(jù)刹悴,使用Debug類采集數(shù)據(jù)步驟如下:
- 在AndroidManifest.xml中添加寫sd卡權(quán)限
- 在問(wèn)題懷疑點(diǎn)處調(diào)用Debug.startMethodTracing("demo");
- 在問(wèn)題結(jié)束點(diǎn)處調(diào)用Debug.stopMethodTracing();,例如攒暇,可以在Activity的onCreate和onPause處分別調(diào)用上述方法土匀。
- 從sd卡中導(dǎo)致trace文件到pc端,利用ddms打開(kāi)trace文件形用。
DDMS方式簡(jiǎn)單就轧,但很粗略。而使用Debug類采集數(shù)據(jù)田度,相對(duì)復(fù)雜妒御,但更精確。
Traceview分析面板上镇饺,有很多的維度携丁,一般來(lái)說(shuō),我們需要分析出那些耗時(shí)或者調(diào)用次數(shù)過(guò)多的函數(shù)兰怠,耗時(shí)的函數(shù)可通過(guò)維度Incl CPU Time分析。調(diào)用次數(shù)過(guò)多的函數(shù)可通過(guò)Cpu Time/Call維度分析李茫。耗時(shí)的函數(shù)需要分析揭保,很容易理解,但調(diào)用次數(shù)過(guò)多的函數(shù)很容易被忽略魄宏,如果view的onMeasure函數(shù)在不需要刷新時(shí)被調(diào)用多次秸侣,這也是值得關(guān)注的問(wèn)題,所以需要分析函數(shù)的調(diào)用次數(shù)。
Traceview應(yīng)用
模擬如下場(chǎng)景味榛,ListView滑動(dòng)卡頓椭坚,在getView方法中sleep一段時(shí)間,導(dǎo)致一幀數(shù)據(jù)無(wú)法在16ms內(nèi)準(zhǔn)備完成搏色,因此滑動(dòng)卡頓善茎。
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = null;
。频轿。垂涯。。航邢。耕赘。
try {
Thread.sleep(50);
} catch (Exception e) {
}
return convertView;
}
使用DDMS采集數(shù)據(jù)分析,按Incl CPU Time降序排列膳殷,traceview面板如下:
因?yàn)镮ncl CPU Time是包含內(nèi)部調(diào)用的其它函數(shù)時(shí)間的操骡,所以從上到下,花時(shí)間最多的就是虛擬機(jī)相關(guān)方法以及ActivityThread的main方法(應(yīng)用線程啟動(dòng)的入口方法)等赚窃。點(diǎn)擊每一個(gè)方法册招,均可以看到此方法自身花費(fèi)時(shí)間、調(diào)用其它方法花費(fèi)時(shí)間以及它的前一調(diào)用方法考榨。一般來(lái)說(shuō)通過(guò)跟蹤調(diào)用鏈跨细,可找到對(duì)應(yīng)問(wèn)題所在。
從ActivityThread的main方法入手河质,parents屬性不用管冀惭,查看children屬性,self即是自身花費(fèi)時(shí)間掀鹅,此時(shí)為0散休,可見(jiàn)耗時(shí)是花在loop方法,一跟跟蹤調(diào)用鏈最終發(fā)現(xiàn)如下:
Adapter類的getView方法中調(diào)用了sleep方法以及setImageResource方法乐尊,而sleep方法耗時(shí)占用整體耗時(shí)的97%戚丸,如此,問(wèn)題原兇已找到扔嵌。
有一個(gè)小竅門限府,在分析某個(gè)方法的耗時(shí)構(gòu)成時(shí),如果此方法顯示有多個(gè)子方法耗時(shí)時(shí)痢缎,則選取耗時(shí)比較最大的子方法繼續(xù)分析胁勺,如下下面的情況:
我們預(yù)先已知listview滑動(dòng)卡頓,那么耗時(shí)最多的應(yīng)該是與listview相關(guān)的函數(shù)独旷,而事實(shí)也是如此署穗,繼續(xù)跟蹤線框內(nèi)容寥裂,即可找到最終問(wèn)題。
Systrace
Systrace與Traceview所不同的是案疲,Systrace它能提供豐富得多的信息封恰,它是對(duì)整機(jī)這段時(shí)間內(nèi)的全面信息反饋,可以查看cpu分配情況褐啡,查看vsync信號(hào)诺舔,查看應(yīng)用具體一幀圖像各階段耗時(shí)情況,甚至還可以查看gc情況春贸,所以Systrace可以從系統(tǒng)高度混萝,整體高度來(lái)查看卡頓問(wèn)題。如果是分析單一應(yīng)用卡頓問(wèn)題萍恕,一定要通過(guò)Systrace來(lái)排除系統(tǒng)問(wèn)題逸嘀,確認(rèn)這段時(shí)間內(nèi)cpu資源足夠,也要查看gc情況允粤。如果某段時(shí)間內(nèi)崭倘,應(yīng)用一幀卡頓,而cpu資源不夠或此時(shí)正在gc类垫,則并不能說(shuō)明是應(yīng)用的問(wèn)題司光。
由于google對(duì)android studio的大力推薦,現(xiàn)在使用eclipse抓取的Systrace悉患,已經(jīng)無(wú)法被chrome識(shí)別了残家,所以需要as抓取Systrace,抓取并打開(kāi)Systrace的步驟如下:
- 打開(kāi)as售躁,打開(kāi)tools菜單坞淮,打開(kāi)android device monitor
- 點(diǎn)擊抓取systrace按鈕,勾選所需的信息陪捷,再確定
- 在機(jī)器上進(jìn)行相應(yīng)操作回窘,生成對(duì)應(yīng)trace文件
- 打開(kāi)chrome瀏覽器,在地址欄上輸入chrome://tracing/市袖,再使用chrome打開(kāi)之前保存的trace文件
Systrace使用W放大啡直,S縮小,A左移苍碟,D右移酒觅,右側(cè)有選擇條,可選擇鼠標(biāo)點(diǎn)擊微峰,也可選擇時(shí)間段標(biāo)記阐滩。操作較為簡(jiǎn)單,不再詳述县忌。
Systrace有幾個(gè)需要注意的點(diǎn)掂榔,首先就是cpu的狀態(tài)問(wèn)題。例如上圖紅框所示症杏,obtainView方法上是無(wú)色的装获,而右邊小部分確是藍(lán)色或綠色,無(wú)色則代表cpu此時(shí)在睡眠狀態(tài)厉颤,藍(lán)色或綠色表示cpu處于運(yùn)行狀態(tài)穴豫。如上圖所示,則可知此時(shí)cpu狀態(tài)異常逼友,是否是調(diào)用了sleep方法導(dǎo)致這一幀卡頓了精肃?可使用左鍵滑動(dòng)選中一段距離,查看這段距離的cpu情況:
Systrace也是可以直接點(diǎn)擊紅色幀(紅色幀即是卡頓幀)帜乞,查看紅色幀的一些基本情況司抱,也能看到對(duì)于紅色幀的處理意見(jiàn)。
Systrace還能夠顯示當(dāng)前的gc情況黎烈,例如:
Systrace還有一個(gè)強(qiáng)大的功能习柠,選中查看某段時(shí)間內(nèi)cpu的情況,如下圖所示照棋,cpu這段時(shí)間內(nèi)有g(shù)c操作资溃,binder調(diào)用,還有打印log烈炭,如果gc操作過(guò)于頻繁溶锭,binder調(diào)用都是會(huì)影響系統(tǒng)性能的,另外log過(guò)多也是會(huì)影響系統(tǒng)性能的符隙。
章節(jié)中的示例趴捅,抓取Systrace,分析膏执,案例簡(jiǎn)單驻售,在Systrace上也一目了解,obtainView時(shí)間太長(zhǎng)了更米,原因是cpu那段時(shí)間都處于sleep狀態(tài)欺栗。
性能優(yōu)化的其它方法
前文介紹的是解決卡頓問(wèn)題的重型武器,也有一些方法可以緩解卡頓或者讓性能更好征峦。通過(guò)繪制原理的介紹迟几,可以清楚地知道,如果UI的層級(jí)越少越好栏笆。怎么查看UI的層級(jí)呢类腮?可以通過(guò)hierarchyviewer工具◎燃樱可以通過(guò)自定義view形式實(shí)現(xiàn)UI層級(jí)的減少蚜枢。UI層級(jí)減少缸逃,也會(huì)緩解過(guò)度繪制問(wèn)題。
另外厂抽,減少界面刷新的次數(shù)也很重要需频,避免不必要的UI界面刷新。降低UI層級(jí)以及減少不必要刷新次數(shù)較為簡(jiǎn)單筷凤,不再詳述昭殉。