[想讓安卓app不再卡頓涯雅?看這篇文章就夠了]
實(shí)現(xiàn)背景
應(yīng)用的使用流暢度,是衡量用戶體驗(yàn)的重要標(biāo)準(zhǔn)之一划乖。Android 由于機(jī)型配置和系統(tǒng)的不同,項(xiàng)目復(fù)雜App場(chǎng)景豐富迷殿,代碼多人參與迭代歷史較久咖杂,代碼可能會(huì)存在很多UI線程耗時(shí)的操作庆寺,實(shí)際測(cè)試時(shí)候也會(huì)偶爾發(fā)現(xiàn)某些業(yè)務(wù)場(chǎng)景發(fā)生卡頓的現(xiàn)象,用戶也經(jīng)常反饋和投訴App使用遇到卡頓诉字。因此懦尝,我們?cè)絹碓疥P(guān)注和提升用戶體驗(yàn)的流暢度問題。
已有方案
在這之前壤圃,我們將反饋的常見卡頓場(chǎng)景陵霉,或測(cè)試過程中常見的測(cè)試場(chǎng)景使用UI自動(dòng)化來重復(fù)操作睹酌,用adb系統(tǒng)工具觀察App的卡頓數(shù)據(jù)情況,試圖重現(xiàn)場(chǎng)景來定位問題洗出。
常用的方式是使用adb SurfaceFlinger服務(wù)和adb gfxinfo功能,在自動(dòng)化操作app的過程中隘梨,使用adb獲取數(shù)據(jù)來監(jiān)控app的流暢情況,發(fā)現(xiàn)出現(xiàn)出現(xiàn)卡頓的時(shí)間段援雇,尋找出現(xiàn)卡頓的場(chǎng)景和操作钻趋。
方式1:adb shell dumpsys SurfaceFlinger
使用‘a(chǎn)db shell dumpsys SurfaceFlinger’命令即可獲取最近127幀的數(shù)據(jù),通過定期執(zhí)行adb命令,獲取幀數(shù)來計(jì)算出幀率FPS冒签。
優(yōu)點(diǎn):命令簡(jiǎn)單辖所,獲取方便,動(dòng)態(tài)頁(yè)面下數(shù)據(jù)直觀顯示頁(yè)面的流暢度在孝;
缺點(diǎn):對(duì)于靜態(tài)頁(yè)面魔招,無法感知它的卡頓情況峦朗。使用FPS在靜態(tài)頁(yè)面情況下,由于獲取數(shù)據(jù)不變,計(jì)算結(jié)果為0,無法有效地衡量靜態(tài)頁(yè)面卡頓程度戈咳;
通過外部adb命令取得的數(shù)據(jù)信息衡量app頁(yè)面卡頓情況的同時(shí),app層面無法在運(yùn)行時(shí)判斷是否卡頓,也就無法記錄下當(dāng)時(shí)運(yùn)行狀態(tài)和現(xiàn)場(chǎng)信息摇肌。
方式2:adb shell dumpsys gfxinfo
使用‘a(chǎn)db shell dumpsys gfxinfo’命令即可獲取最新128幀的繪制信息雨饺,詳細(xì)包括每一幀繪制的Draw,Process惑淳,Execute三個(gè)過程的耗時(shí)额港,如果這三個(gè)時(shí)間總和超過16.6ms即認(rèn)為是發(fā)生了卡頓。
優(yōu)點(diǎn):命令簡(jiǎn)單歧焦,獲取方便移斩,不僅可以計(jì)算幀率肚医,還可以觀察卡頓時(shí)每一幀的瓶頸處于哪個(gè)維度(onDraw,onProcess向瓷,onExecute)扛施;
缺點(diǎn):同方式1擁有一樣的缺點(diǎn)嚼鹉,無法衡量靜態(tài)頁(yè)面下的卡頓程度;app層面依然無法在發(fā)生卡頓時(shí)獲取運(yùn)行狀態(tài)和信息,導(dǎo)致跟進(jìn)和重現(xiàn)困難扭粱。
已有的兩種方案比較適合衡量回歸卡頓問題的修復(fù)效果和判斷某些特定場(chǎng)景下是否有卡頓情況圆到,然而雇锡,這樣的方式有幾個(gè)明顯的不足:
1壳炎、一般很難構(gòu)造實(shí)際用戶卡頓的環(huán)境來重現(xiàn);
2长搀、這種方式操作起來比較麻煩宇弛,需編寫自動(dòng)化用例,無法覆蓋大量的可疑場(chǎng)景源请,測(cè)試重現(xiàn)耗時(shí)耗人力枪芒;
3、無法衡量靜態(tài)頁(yè)面的卡頓情況谁尸;
4舅踪、出現(xiàn)卡頓的時(shí)候app無法及時(shí)獲取運(yùn)行狀態(tài)和信息,開發(fā)定位困難良蛮。
全新方案
基于這樣的痛點(diǎn)抽碌,我們希望能使用一套有效的檢測(cè)機(jī)制,能夠覆蓋各種可能出現(xiàn)的卡頓場(chǎng)景背镇,一旦發(fā)生卡頓咬展,能幫助我們更方便地定位耗時(shí)卡頓發(fā)生的地方泽裳,記錄下具體的信息和堆棧瞒斩,直接從代碼程度給到開發(fā)定位卡頓問題。我們?cè)O(shè)想的Android卡頓監(jiān)控系統(tǒng)需要達(dá)到幾項(xiàng)基本功能:
1涮总、如何有效地監(jiān)控到App發(fā)生卡頓胸囱,同時(shí)在發(fā)生卡頓時(shí)正確記錄app的狀態(tài),如堆棧信息瀑梗,CPU占用烹笔,內(nèi)存占用,IO使用情況等等抛丽;
2谤职、統(tǒng)計(jì)到的卡頓信息上報(bào)到監(jiān)控平臺(tái),需要處理分析分類上報(bào)內(nèi)容亿鲜,并通過平臺(tái)Web直觀簡(jiǎn)便地展示允蜈,供開發(fā)跟進(jìn)處理。
如何從App層面監(jiān)控卡頓?
我們的思路是饶套,一般主線程過多的UI繪制漩蟆、大量的IO操作或是大量的計(jì)算操作占用CPU,導(dǎo)致App界面卡頓妓蛮。只要我們能在發(fā)生卡頓的時(shí)候怠李,捕捉到主線程的堆棧信息和系統(tǒng)的資源使用信息,即可準(zhǔn)確分析卡頓發(fā)生在什么函數(shù)蛤克,資源占用情況如何捺癞。那么問題就是如何有效檢測(cè)Android主線程的卡頓發(fā)生,目前業(yè)界兩種主流有效的app監(jiān)控方式如下咖耘,在《Android卡頓監(jiān)控方式實(shí)現(xiàn)》這篇文章中我將分別詳細(xì)闡述這兩者的特點(diǎn)和實(shí)現(xiàn)翘簇。
1、利用UI線程的Looper打印的日志匹配儿倒;
2版保、使用Choreographer.FrameCallback
方式3: 利用UI線程的Looper打印的日志匹配判斷是否卡頓
Android主線程更新UI。如果界面1秒鐘刷新少于60次夫否,即FPS小于60彻犁,用戶就會(huì)產(chǎn)生卡頓感覺。簡(jiǎn)單來說凰慈,Android使用消息機(jī)制進(jìn)行UI更新汞幢,UI線程有個(gè)Looper,在其loop方法中會(huì)不斷取出message微谓,調(diào)用其綁定的Handler在UI線程執(zhí)行森篷。如果在handler的dispatchMesaage方法里有耗時(shí)操作,就會(huì)發(fā)生卡頓豺型。
只要檢測(cè)msg.target.dispatchMessage(msg) 的執(zhí)行時(shí)間仲智,就能檢測(cè)到部分UI線程是否有耗時(shí)的操作,從而判斷是否發(fā)生了卡頓姻氨,并打印UI線程的堆棧信息钓辆。
優(yōu)點(diǎn):用戶使用app或者測(cè)試過程中都能從app層面來監(jiān)控卡頓情況,一旦出現(xiàn)卡頓能記錄app狀態(tài)和信息肴焊, 只要dispatchMesaage執(zhí)行耗時(shí)過大都會(huì)記錄下來前联,不再有前面兩種adb方式面臨的問題與不足。
缺點(diǎn):需另開子線程獲取堆棧信息娶眷,會(huì)消耗少量系統(tǒng)資源似嗤。
方式4: 利用Choreographer.FrameCallback監(jiān)控卡頓
我們知道, Android系統(tǒng)每隔16ms發(fā)出VSYNC信號(hào)届宠,來通知界面進(jìn)行重繪烁落、渲染壳咕,每一次同步的周期為16.6ms,代表一幀的刷新頻率顽馋。SDK中包含了一個(gè)相關(guān)類谓厘,以及相關(guān)回調(diào)。理論上來說兩次回調(diào)的時(shí)間周期應(yīng)該在16ms寸谜,如果超過了16ms我們則認(rèn)為發(fā)生了卡頓竟稳,利用兩次回調(diào)間的時(shí)間周期來判斷是否發(fā)生卡頓(這個(gè)方案是Android 4.1 API 16以上才支持)。
這個(gè)方案的原理主要是通過Choreographer類設(shè)置它的FrameCallback函數(shù)熊痴,當(dāng)每一幀被渲染時(shí)會(huì)觸發(fā)回調(diào)FrameCallback他爸, FrameCallback回調(diào)void doFrame (long frameTimeNanos)函數(shù)。一次界面渲染會(huì)回調(diào)doFrame方法果善,如果兩次doFrame之間的間隔大于16.6ms說明發(fā)生了卡頓诊笤。
優(yōu)點(diǎn):不僅可用來從app層面來監(jiān)控卡頓,同時(shí)可以實(shí)時(shí)計(jì)算幀率和掉幀數(shù)巾陕,實(shí)時(shí)監(jiān)測(cè)App頁(yè)面的幀率數(shù)據(jù)讨跟,一旦發(fā)現(xiàn)幀率過低,可自動(dòng)保存現(xiàn)場(chǎng)堆棧信息鄙煤。
缺點(diǎn):需另開子線程獲取堆棧信息晾匠,會(huì)消耗少量系統(tǒng)資源。
總結(jié)下上述四種方案的對(duì)比情況:
SurfaceFlinger | gfxinfo | Looper.loop | Choreographer.FrameCallback | |
---|---|---|---|---|
監(jiān)控是否卡頓 | √ | √ | √ | √ |
支持靜態(tài)頁(yè)面卡頓檢測(cè) | × | × | √ | √ |
支持計(jì)算幀率 | √ | √ | × | √ |
支持獲取App運(yùn)行信息 | × | × | √ | √ |
實(shí)際項(xiàng)目使用中梯刚,我們一開始兩種監(jiān)控方式都用上凉馆,上報(bào)的兩種方式收集到的卡頓信息我們分開處理,發(fā)現(xiàn)卡頓的監(jiān)控效果基本相當(dāng)亡资。同一個(gè)卡頓發(fā)生時(shí)澜共,兩種監(jiān)控方式都能記錄下來。 由于Choreographer.FrameCallback的監(jiān)控方式不僅用來監(jiān)控卡頓锥腻,也方便用來計(jì)算實(shí)時(shí)幀率嗦董,因此我們現(xiàn)在只使用Choreographer.FrameCallback來監(jiān)控app卡頓情況。
痛點(diǎn)1:如何保證捕獲卡頓堆棧的準(zhǔn)確性旷太?
細(xì)心的同學(xué)可以發(fā)現(xiàn)展懈,我們通過上述兩種方案(Looper.loop和Choreographer.FrameCallback)可以判斷是當(dāng)前主線程是否發(fā)生了卡頓销睁,進(jìn)而在計(jì)算發(fā)現(xiàn)卡頓后的時(shí)刻dump下了主線程的堆棧信息供璧。實(shí)際上,通過一個(gè)子線程冻记,監(jiān)控主線程的活動(dòng)情況睡毒,計(jì)算發(fā)現(xiàn)超過閾值后dump下主線程的堆棧,那么生成的堆棧文件只是捕捉了一個(gè)時(shí)刻的現(xiàn)場(chǎng)快照冗栗。打個(gè)不太恰當(dāng)?shù)谋确窖莨耍喈?dāng)于閉路電視監(jiān)控只拍下了兇案發(fā)生后的慘狀供搀,而并沒有錄下這個(gè)案件發(fā)生的過程,那么作為警察的你只看到了結(jié)局钠至,依然很難判斷案情和兇手葛虐。在實(shí)際的運(yùn)用中,我們也發(fā)現(xiàn)這種方式下獲取到的堆棧情況棉钧,查看相關(guān)的代碼和函數(shù)屿脐,經(jīng)常已經(jīng)不是發(fā)生卡頓的代碼了。
如圖所示宪卿,主線程在T1~T2時(shí)間段內(nèi)發(fā)生卡頓的诵,上述方案中獲取卡頓堆棧的時(shí)機(jī)已經(jīng)是T2時(shí)刻。實(shí)際卡頓可能是這段時(shí)間內(nèi)某個(gè)函數(shù)的耗時(shí)過大導(dǎo)致卡頓佑钾,而不一定是T2時(shí)刻的問題西疤,如此捕獲的卡頓信息就無法如實(shí)反應(yīng)卡頓的現(xiàn)場(chǎng)。
我們看看在這之前微信iOS主線程卡頓監(jiān)控系統(tǒng)是如何實(shí)現(xiàn)的捕獲堆棧休溶。微信iOS的方案是起檢測(cè)線程每1秒檢查一次代赁,如果檢測(cè)到主線程卡頓,就將所有線程的函數(shù)調(diào)用堆棧dump到內(nèi)存中兽掰。本質(zhì)上管跺,微信iOS方案的計(jì)時(shí)起點(diǎn)是固定的,檢查次數(shù)也是固定的禾进。如果任務(wù)1執(zhí)行花費(fèi)了較長(zhǎng)的時(shí)間導(dǎo)致卡頓豁跑,但由于監(jiān)控線程是隔1秒掃一次的,可能到了任務(wù)N才發(fā)現(xiàn)并dump下來堆棧泻云,并不能抓到關(guān)鍵任務(wù)1的堆棧艇拍。這樣的情況的確是存在的,只不過現(xiàn)上監(jiān)控量大走人海戰(zhàn)術(shù)宠纯,通過概率分布抓到卡頓點(diǎn)卸夕,但依然不是最佳的捕獲方案。
因此婆瓜,擺在我們面前的是如何更加精準(zhǔn)地獲取卡頓堆棧快集。為了卡頓堆棧的準(zhǔn)確度,我們想要能獲取一段時(shí)間內(nèi)的堆棧廉白,而不是一個(gè)點(diǎn)的堆棧个初,如下圖:
我們采用高頻采集的方案來獲取一段卡頓時(shí)間內(nèi)的多個(gè)堆棧,而不再是只有一個(gè)點(diǎn)的堆棧猴蹂。這樣的方案的優(yōu)點(diǎn)是保證了監(jiān)控的完備性院溺,整個(gè)卡頓過程的堆棧都得以采樣、收集和落地磅轻。
具體做法是在子線程監(jiān)控的過程中珍逸,每一輪log輸出或是每一幀開始啟動(dòng)monitor時(shí)逐虚,我們便已經(jīng)開啟了高頻采樣收集主線程堆棧的工作了。當(dāng)下一輪log或者下一幀結(jié)束monitor時(shí)谆膳,我們判斷是否發(fā)生卡頓(計(jì)算耗時(shí)是否超過閾值)叭爱,來決定是否將內(nèi)存中的這段堆棧集合落地到文件存儲(chǔ)。也就是說漱病,每一次卡頓的發(fā)生涤伐,我們記錄了整個(gè)卡頓過程的多個(gè)高頻采樣堆棧。由此精確地記錄下整個(gè)兇案發(fā)生的詳細(xì)過程缨称,供上報(bào)后分析處理(后文會(huì)闡述如何從一次卡頓中多個(gè)堆棧信息中提取出關(guān)鍵堆棧)凝果。
采樣頻率與性能消耗
目前我們的策略是判斷一個(gè)卡頓是否發(fā)生的耗時(shí)閾值是80ms(5*16.6ms),當(dāng)一個(gè)卡頓達(dá)80ms的耗時(shí)睦尽,采集1~2個(gè)堆椘骶唬基本可以定位到耗時(shí)的堆棧。因此采樣堆棧的頻率我們?cè)O(shè)為52ms(經(jīng)驗(yàn)值)当凡。
當(dāng)然山害,高頻采集堆棧的方案,必然會(huì)導(dǎo)致app性能上帶來的影響沿量。為此浪慌,為了評(píng)估對(duì)App的性能影響,在上述默認(rèn)設(shè)置的情況下朴则,我們做一個(gè)簡(jiǎn)單的測(cè)試實(shí)驗(yàn)觀察权纤。實(shí)驗(yàn)方法:ViVoX9 上運(yùn)行微信讀書App,使用卡頓監(jiān)控與高頻采樣乌妒,和不使用卡頓監(jiān)控的情況下汹想,保持兩次的操作動(dòng)作相同,分析性能差異撤蚊,數(shù)據(jù)如下:
關(guān)閉監(jiān)控 | 打開監(jiān)控 | 對(duì)比情況(上漲) | ||
---|---|---|---|---|
CPU | 1.07% | 1.15% | 0.08% | |
Memory | Native Heap | 38794 | 38894 | 100 kB |
Dalvik Heap | 25889 | 26984 | 1095 kB | |
Dalvik Other | 2983 | 3099 | 116 kB | |
.so mmap | 38644 | 38744 | 100 kB |
沒有線程快照 | 加上線程快照 | |||
---|---|---|---|---|
性能指標(biāo) | 2.4.5.368.91225 | 2.4.8.376.91678 | 上漲 | |
CPU | CPU | 63 | 64 | 0.97% |
流量KB | Flow | 28624 | 28516 | |
內(nèi)存KB | NativeHeap | 59438 | 60183 | 1.25% |
DalvikHeap | 7066 | 7109 | 0.61% | |
DalvikOther | 6965 | 6992 | 0.40% | |
Sommap | 22206 | 22164 | ||
日志大小KB | file size | 294893 | 1561891 | 430% |
壓縮包大小KB | zip size | 15 | 46 | 206% |
從實(shí)驗(yàn)結(jié)果可知古掏,高頻采樣對(duì)性能消耗很小,可以不影響用戶體驗(yàn)侦啸。
監(jiān)控使用Choreographer.FrameCallback, 采樣頻率設(shè)52ms)槽唾,最終結(jié)果是性能消耗帶來的影響很小,可忽略:
1)監(jiān)控代碼本身對(duì)主線程有一定的耗時(shí)光涂,但影響很小庞萍,約0.1ms/S;
2)卡頓監(jiān)控開啟后顶捷,增加0.1%的CPU使用挂绰;
3)卡頓監(jiān)控開啟后屎篱,增加Davilk Heap內(nèi)存約1MB服赎;
4)對(duì)于流量葵蒂,文件可按天寫入,壓縮文件最大約100KB重虑,一天上傳一次
痛點(diǎn)2:海量卡頓堆棧后該如何處理践付?
卡頓堆棧上報(bào)到平臺(tái)后,需要對(duì)上報(bào)的文件進(jìn)行分析缺厉,提取和聚類過程永高,最終展示到卡頓平臺(tái)。前面我們提到提针,每一次卡頓發(fā)生時(shí)命爬,會(huì)高頻采樣到多個(gè)堆棧信息描述著這一個(gè)卡頓。做個(gè)最小的估算辐脖,每天上報(bào)收集2000個(gè)用戶卡頓文件饲宛,每個(gè)卡頓文件dump下了用戶遇到的10個(gè)卡頓,每個(gè)卡頓高頻收集到30個(gè)堆棧嗜价,這就已經(jīng)產(chǎn)生20001030=60W個(gè)堆棧艇抠。按照這個(gè)量級(jí)發(fā)展,一個(gè)月可產(chǎn)生上千萬的堆棧信息久锥,每個(gè)堆棧還是幾十行的函數(shù)調(diào)用關(guān)系家淤。這么大量的信息對(duì)存儲(chǔ),分析瑟由,頁(yè)面展示等均帶來相當(dāng)大的壓力絮重。很快就能撐爆存儲(chǔ)層,平臺(tái)無法展示這么大量的數(shù)據(jù)歹苦,開發(fā)更是沒辦法處理這些多的堆棧問題绿鸣。因而,海量卡頓堆棧成為我們另外一個(gè)面對(duì)的難題暂氯。
在一個(gè)卡頓過程中潮模,一般卡頓發(fā)生在某個(gè)函數(shù)的調(diào)用上罢缸,在這多個(gè)堆棧列表中师逸,我們把每個(gè)堆棧都做一次hash處理后進(jìn)行排重分析,有很大的幾率會(huì)是dump到同一個(gè)堆棧hash蔼啦,如下圖:
我們對(duì)一個(gè)卡頓中多個(gè)堆棧進(jìn)行統(tǒng)計(jì)辣吃,去重后找出最高重復(fù)次數(shù)的堆棧动遭,發(fā)現(xiàn)堆棧C出現(xiàn)了3次,這次卡頓很有可能就是卡在堆棧3反映的函數(shù)調(diào)用上神得。由于采樣頻率不低厘惦,因此出現(xiàn)卡頓后一般都有不少的卡頓,如此可找出重復(fù)次數(shù)最高的堆棧哩簿,作為重點(diǎn)分析卡頓問題宵蕉,從而進(jìn)行修復(fù)酝静。
舉個(gè)實(shí)際上報(bào)數(shù)據(jù)例子,可以由下圖看到羡玛,一個(gè)卡頓如序號(hào)3别智,在T1~T2時(shí)間段共收集到62個(gè)堆棧,我們發(fā)現(xiàn)大部分堆棧都是一樣的稼稿,于是我們把堆棧hash后嘗試去重薄榛,發(fā)現(xiàn)排重后只有2個(gè)堆棧,而其中某個(gè)堆棧重復(fù)了59次让歼,我們可以重點(diǎn)關(guān)注和處理這個(gè)堆棧反映出的卡頓問題敞恋。
把一個(gè)卡頓抽離成一個(gè)關(guān)鍵的堆棧的思路,可以大大降低了數(shù)據(jù)量谋右, 前面提及60W個(gè)堆棧就可以縮減為2W個(gè)堆棧(2000101=2W)耳舅。
按照這個(gè)方法,處理后的每個(gè)卡頓只剩下一個(gè)堆棧倚评,進(jìn)而每個(gè)卡頓都有唯一的標(biāo)識(shí)(hash)浦徊。到此,我們還可以對(duì)卡頓進(jìn)行聚類操作天梧,進(jìn)一步排重和縮小數(shù)據(jù)量盔性。分類前對(duì)每個(gè)堆棧,根據(jù)業(yè)務(wù)的不同設(shè)置好過濾關(guān)鍵字呢岗,提取出感興趣的代碼行冕香,去除其他冗余的系統(tǒng)函數(shù)后進(jìn)行歸類。目前主要有兩種方式的分類:
1后豫、按堆棧最外層分類悉尾,這種分類方法把同樣入口的函數(shù)導(dǎo)致的卡頓收攏到一起,開發(fā)修復(fù)對(duì)應(yīng)入口的函數(shù)來解決卡頓挫酿,然而這種方式有一定的風(fēng)險(xiǎn)构眯,可能同樣入口但最終調(diào)用不同的函數(shù)導(dǎo)致的卡頓則會(huì)被忽略;
2早龟、按堆棧最內(nèi)層分類惫霸,這種分類方法能收攏同樣根源問題的卡頓,缺點(diǎn)就是可能忽略調(diào)用方可能有多個(gè)業(yè)務(wù)入口葱弟,會(huì)造成fix不全面壹店。
當(dāng)然,這兩種方式的聚類芝加,從一定程度上分類大量的卡頓硅卢,但不太好控制的是,究竟要取堆棧的多少層作為識(shí)別分類。層數(shù)越多将塑,則聚類結(jié)果變多脉顿,分類更細(xì),問題零碎抬旺;層數(shù)越少弊予,則聚類結(jié)果變少祥楣,達(dá)不到分類的效果开财。這是一個(gè)權(quán)衡的過程,實(shí)際則按照一定的嘗試效果后去劃分層數(shù)误褪,如微信iOS卡頓監(jiān)控采用的策略是一級(jí)分類按最內(nèi)層倒數(shù)2層分類责鳍,二級(jí)分類按最內(nèi)層倒數(shù)4層。
對(duì)于我們產(chǎn)品兽间,目前我們沒有按層數(shù)最內(nèi)或最外來劃分历葛,直接過濾出感興趣的關(guān)鍵字的代碼后直接分類。這樣的分類效果下來數(shù)據(jù)量級(jí)在承受范圍內(nèi)嘀略,如之前的2W堆椥羧埽可聚類剩下大約2000個(gè)(視具體聚類結(jié)果)。同時(shí)帜羊,每天新上報(bào)的堆棧都跟歷史數(shù)據(jù)對(duì)比聚合咒程,只過濾出未重復(fù)的堆棧,更進(jìn)一步地縮減上報(bào)堆棧的真正存儲(chǔ)量讼育。
卡頓監(jiān)控系統(tǒng)的處理流程
用戶上報(bào)
目前我們的策略是:
1帐姻、通過后臺(tái)配置下發(fā),灰度0.2%的用戶量進(jìn)行卡頓監(jiān)控和上報(bào)奶段;
2饥瓷、如果用戶反饋有卡頓問題,也可實(shí)時(shí)撈取卡頓日志來分析痹籍;
3呢铆、每天灰度的用戶一個(gè)機(jī)器上報(bào)一次,上報(bào)后刪除文件不影響存儲(chǔ)空間蹲缠。
后臺(tái)解析
1刺洒、主要負(fù)責(zé)處理上報(bào)的卡頓文件,過濾吼砂、去重逆航、分類、反解堆棧渔肩、入庫(kù)等流程因俐;
2、自動(dòng)回歸修復(fù)好的卡頓問題,讀取tapd 卡頓bug單的修復(fù)結(jié)果抹剩,更新平臺(tái)展示撑帖,計(jì)算修復(fù)好的卡頓問題,后續(xù)版本是否重新出現(xiàn)(修復(fù)不徹底)
平臺(tái)展示
上報(bào)處理后的卡頓展示平臺(tái)
http://test.itil.rdgz.org/wel...
主要展示卡頓處理后的數(shù)據(jù):
1澳眷、以版本為維度展示卡頓問題列表胡嘿,按照卡頓上報(bào)重復(fù)的次數(shù)降序列出;
2钳踊、歸類后展示每個(gè)卡頓的關(guān)鍵耗時(shí)代碼衷敌,也可查看全部堆棧內(nèi)容;
3拓瞪、支持操作卡頓記錄缴罗,如搜索卡頓,提t(yī)apd單祭埂,標(biāo)注已解決等面氓;
4、展示每個(gè)版本的卡頓問題修復(fù)數(shù)據(jù)情況蛆橡,版本分布舌界,監(jiān)控修復(fù)后是否重現(xiàn)等。
自動(dòng)提單
實(shí)際使用中泰演,為了增強(qiáng)跟進(jìn)效果呻拌,我們?cè)O(shè)立一些規(guī)則,比如卡頓重復(fù)上報(bào)超過100次粥血,卡頓耗時(shí)達(dá)到1000ms等柏锄,自動(dòng)提t(yī)apd bug單給開發(fā)處理,系統(tǒng)也會(huì)自動(dòng)更新卡頓問題的修復(fù)情況和數(shù)據(jù)复亏,開發(fā)只需定期review tapd bug單處理修復(fù)卡頓問題即可趾娃,整個(gè)卡頓系統(tǒng)從監(jiān)控,上報(bào)缔御,分析抬闷,聚類,展示耕突,提單到回歸笤成,整個(gè)流程自動(dòng)化實(shí)現(xiàn),不再需要人工介入眷茁。
實(shí)際應(yīng)用效果
1炕泳、接入產(chǎn)品:微信讀書,企業(yè)微信上祈,QQ郵箱
2培遵、應(yīng)用場(chǎng)景:現(xiàn)網(wǎng)用戶的監(jiān)控浙芙,發(fā)布前測(cè)試的監(jiān)控,每天自動(dòng)化運(yùn)行的監(jiān)控
3籽腕、發(fā)現(xiàn)問題:三個(gè)多月時(shí)間嗡呼,歸類后的卡頓過萬,提bug單約500皇耗,開發(fā)已解決超過200個(gè)卡頓問題
卡頓監(jiān)控的組件化
考慮到Android卡頓監(jiān)控的通用性南窗,除了應(yīng)用于Android WeRead中,我們也推廣到廣研的其他產(chǎn)品中郎楼,如企業(yè)微信万伤,QQ郵箱。因此箭启,在開發(fā)GG的努力下壕翩,推出了卡頓監(jiān)控庫(kù)http://git.code.oa.com/moai/m... 蛉迹,其他Android產(chǎn)品可快速接入卡頓監(jiān)控的SDK來監(jiān)控app卡頓情況傅寡。
目前monitor卡頓監(jiān)控庫(kù)主要有監(jiān)控主線程卡頓情況,獲取平均幀率使用情況北救,高頻采樣和獲取卡頓信息等基本功能荐操。這里要注意幾點(diǎn):
1、采樣堆棧信息的頻率和卡頓耗時(shí)的閾值均可在SDK中設(shè)置珍策;
2托启、SDK默認(rèn)判斷一個(gè)卡頓是否發(fā)生的耗時(shí)閾值是80ms(5*16.6ms)
3、采樣堆棧的頻率是52ms(約3幀+攘宙,盡量錯(cuò)開系統(tǒng)幀率的節(jié)奏屯耸,堆棧可盡量落到繪制幀過程中)
4蹭劈、啟動(dòng)監(jiān)控后疗绣,卡頓日志就會(huì)不斷通過內(nèi)部的writer輸出,實(shí)現(xiàn)MonitorLogWriter.setDelegate才能獲取這些日志铺韧,具體的日志落地和上報(bào)策略因?yàn)楦鱾€(gè)App不同所以沒有集成到SDK中
5多矮、monitor start后一直監(jiān)控主線程, 包括切換到后臺(tái)時(shí)也會(huì)哈打,直到主動(dòng)stop或者app被kill塔逃。所以在切后臺(tái)時(shí)要主動(dòng)stop monitor,切前臺(tái)時(shí)要重新start
1.組件引入方式
2.主線程卡頓監(jiān)控的使用方式
1)啟動(dòng)監(jiān)控
2)停止監(jiān)控
3)獲取卡頓信息
app中加入監(jiān)控卡頓SDK后,會(huì)實(shí)時(shí)輸出卡頓的時(shí)間點(diǎn)和堆棧信息料仗,我們將這些信息寫入日志文件落地湾盗,同時(shí)每天固定場(chǎng)景上報(bào)到服務(wù)器,如每天上報(bào)一次立轧,用戶打開app后進(jìn)行上報(bào)等策略格粪。收集不同用戶不同手機(jī)不同場(chǎng)景下的所有卡頓堆棧信息丙挽,可供分析,定位和優(yōu)化問題匀借。