解決Android 高CPU占用率的問題
背景
最近測(cè)試測(cè)試APP的一個(gè)功能,發(fā)現(xiàn)點(diǎn)擊頁(yè)面上的按鈕后,CPU占有率比之前的版本要高,達(dá)到了4%,之前的版本只有不到1%。由于兩個(gè)版本之間代碼提交特別多,無(wú)法直接通過(guò)代碼變動(dòng)來(lái)對(duì)比分析。只好直接通過(guò)AS工具profiler來(lái)分析應(yīng)用CPU占用了,看下如何優(yōu)化。
分析過(guò)程
首先從測(cè)試同學(xué)口中知道了CPU占用出現(xiàn)異常的場(chǎng)景是點(diǎn)擊頁(yè)面上的功能A的按鈕。OK,那我們就從點(diǎn)擊這個(gè)按鈕入手。首先打開Profiler,選擇對(duì)應(yīng)的APP進(jìn)程,開始監(jiān)聽當(dāng)前進(jìn)程的CPU占用率。
雙擊CPU一行,我們進(jìn)入到CPU詳情頁(yè)面,如下:
可以看到在左側(cè),有4個(gè)選項(xiàng),且下方有record按鈕。這里的含義是,我們通過(guò)點(diǎn)擊record后,profile會(huì)開始記錄接下來(lái)一段時(shí)間內(nèi),詳細(xì)的CPU占用信息,記錄哪些信息呢,通過(guò)上述四個(gè)選項(xiàng)供我們選擇。
- Callstack Sample
會(huì)顯示當(dāng)前這段時(shí)間內(nèi),涉及到的進(jìn)程以及調(diào)用棧都有哪些,會(huì)精細(xì)到進(jìn)程和具體代碼。
- System Trace
會(huì)顯示詳細(xì)的信息,包括VSYNC UI繪制信號(hào),內(nèi)存占用(不是詳細(xì)內(nèi)存占用),各個(gè)線程的運(yùn)行時(shí)間和CPU占用。也會(huì)精確到代碼,但是不會(huì)特別詳細(xì)。適合分析record中等時(shí)長(zhǎng)的數(shù)據(jù)。此外這里包含的信息會(huì)很多,有助于先手分析。
- Java/Kotlin Method Trace
內(nèi)容更詳細(xì),會(huì)精細(xì)到各行代碼,但是這個(gè)不適合record抓取太長(zhǎng)時(shí)間的文件,因?yàn)锳S分析會(huì)占用很長(zhǎng)時(shí)間。
我們先選擇SystemTrace,點(diǎn)擊Record開始記錄信息,我們接著點(diǎn)擊功能A按鈕,開始復(fù)現(xiàn)問題場(chǎng)景,問題復(fù)現(xiàn),點(diǎn)擊Stop按鈕停止抓取,接著AS會(huì)自動(dòng)解析文件,生成我們?cè)敿?xì)信息,如下圖:
可以看到UI的刷新VSYNC信號(hào)刷新很頻繁,對(duì)應(yīng)下方主線程代碼,存在不少峰值。我們放大下方代碼峰值,找到最下方峰頂代碼,
可以看到下方在layout中,不停的obtainview,這里有可能是一個(gè)列表,ListView或者rectclerview,在不停的更新數(shù)據(jù)。
我們接著抓一份Java Kotlin Method Trace分析看下:
注意這里要點(diǎn)開:
然后我們隨意找到一個(gè)峰值,查看其代碼源:
這里可以直接直觀的看到定位到了我們的代碼,LogViewer控件,我們點(diǎn)進(jìn)去查看源碼,會(huì)發(fā)現(xiàn)里邊定義了一個(gè)listView。這個(gè)ListView的功能是在APP上顯示logcat日志,當(dāng)點(diǎn)擊功能A按鈕時(shí),會(huì)產(chǎn)生大量日志,然后每次需要打印一行日志時(shí)候,就會(huì)全部更新listView的所有控件,(代碼內(nèi)容不方便粘貼)所以造成APP UI繪制高頻率進(jìn)行,導(dǎo)致CPU的占用率居高。
定位到問題了:ListView不停的刷新UI,導(dǎo)致VSYNC不停的觸發(fā)繪制,導(dǎo)致CPU占用率高
解決問題
現(xiàn)在我們定位到了問題所在,那么怎么解決呢?
第一步,極端化,直接去掉對(duì)應(yīng)UI
首先我們最直接的方法就是把這個(gè)UI直接屏蔽掉,不去初始化以及展示這個(gè)UI。
這種處理下,我們看下數(shù)據(jù),如圖,很明顯,VSYNC觸發(fā)周期長(zhǎng)了,UI繪制頻率下來(lái)了,交給測(cè)試一看,CPU占用率降到了1.1%, 直接降了3%。
但是直接去掉這個(gè)UI,其實(shí)不是很妥,畢竟這樣相當(dāng)于這個(gè)UI需求給廢了。 我們從ListView代碼入手,ListView會(huì)產(chǎn)生很多個(gè)子View,在我們這個(gè)需求中,需要顯示logcat日志,意味著,每一行日志都會(huì)新生成一個(gè)view放入到logcat中,日志越打越多,view對(duì)象也越多。不僅UI繪制頻繁,內(nèi)存也會(huì)持續(xù)上升。所以這里想優(yōu)化只能減少view的個(gè)數(shù),但是,日志內(nèi)容不能少,個(gè)數(shù)怎么減呢?比如把所有內(nèi)容做一個(gè)整體,作為一個(gè)字符串顯示到控件中,但這樣就不需要listView了,直接一個(gè)TextView即可。我們?cè)囅逻@種方案。
第二步,嘗試TextView替換listview實(shí)現(xiàn)需求
將布局替換為TextView,通過(guò)textView的append屬性來(lái)實(shí)現(xiàn)追加日志內(nèi)容??梢钥吹叫Ч銎娴暮?,VSYNC信號(hào)不會(huì)很頻繁,且沒有生成多余的對(duì)象。
性能狗測(cè)試了一下,CPU占用率為1.7%。
但是TextView也有弊端,對(duì)于數(shù)據(jù)的操作沒有l(wèi)istView和recyclerview那么精細(xì)化,如果因?yàn)闃I(yè)務(wù)需求,仍然想用listview怎么辦呢?
第三步,嘗試優(yōu)化listView
實(shí)際需求中,如果我們繞不開listView,那么就只能想辦法去優(yōu)化它了。從之前的數(shù)據(jù)來(lái)看,是因?yàn)閁I刷新太頻繁,那么我們降低UI的刷新頻率呢? 這里改動(dòng)了一下代碼:緩存日志信息,每過(guò)500ms才去刷新UI,將緩存的日志顯示到listView中,這樣改完后,看下效果:
有一些好轉(zhuǎn),使用性能狗測(cè)試下,看看,結(jié)果CPU占用率為2.4%,也優(yōu)化了不少。
總結(jié)
對(duì)于這種問題,利用好工具profiler對(duì)程序進(jìn)行分析。能夠快速找到問題原因的基礎(chǔ)在于對(duì)工具的熟練程度,對(duì)于AS工具的使用,可以直接參考官方文檔的介紹:https://developer.android.google.cn/studio/profile/power-profiler?hl=zh-cn
以上就是解決Android 高CPU占用率的問題的詳細(xì)內(nèi)容,更多關(guān)于Android高CPU占用率的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Android、Flutter為不同的CPU架構(gòu)包打包APK(v7a、v8a、x86區(qū)別)
- Python獲取android設(shè)備cpu和內(nèi)存占用情況
- 淺析AndroidStudio3.0最新 Android Profiler分析器(cpu memory network 分析器)
- Android編程實(shí)現(xiàn)獲取系統(tǒng)內(nèi)存、CPU使用率及狀態(tài)欄高度的方法示例
- Android獲取設(shè)備CPU核數(shù)、時(shí)鐘頻率以及內(nèi)存大小的方法
- 解析Android獲取系統(tǒng)cpu信息,內(nèi)存,版本,電量等信息的方法詳解
- android獲取手機(jī)cpu并判斷是單核還是多核
- Android 輕松獲取CPU型號(hào)的方法
相關(guān)文章
Android藍(lán)牙服務(wù)查找附近設(shè)備分析探索
這篇文章主要介紹了Android藍(lán)牙服務(wù)實(shí)現(xiàn)查找附近設(shè)備,了解內(nèi)部原理是為了幫助我們做擴(kuò)展,同時(shí)也是驗(yàn)證了一個(gè)人的學(xué)習(xí)能力,如果你想讓自己的職業(yè)道路更上一層樓,這些底層的東西你是必須要會(huì)的2023-01-01Android?Flutter在點(diǎn)擊事件上添加動(dòng)畫效果實(shí)現(xiàn)全過(guò)程
這篇文章主要給大家介紹了關(guān)于Android?Flutter在點(diǎn)擊事件上添加動(dòng)畫效果實(shí)現(xiàn)的相關(guān)資料,通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)Android具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2023-03-03為Android系統(tǒng)添加config.xml 新配置的設(shè)置
這篇文章主要介紹了為Android系統(tǒng)添加config.xml 新配置的設(shè)置,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-03-03ANDROID中自定義對(duì)話框AlertDialog使用示例
這篇文章主要為大家詳細(xì)介紹了Android中自定義對(duì)話框AlertDialog使用示例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-12-12android判斷phonegap是否聯(lián)網(wǎng)且加載super.loadUrl網(wǎng)址
android判斷phonegap是否聯(lián)網(wǎng)動(dòng)態(tài)加載super.loadUrl網(wǎng)址,接下來(lái)本文所提供的知識(shí)會(huì)幫助你解決以上問題,感興趣的你可不要錯(cuò)過(guò)了哈2013-02-02Android App開發(fā)中RecyclerView控件的基本使用教程
這篇文章主要介紹了Android App開發(fā)中RecyclerView控件的基本使用教程,RecyclerView在Android 5.0之后伴隨著Material Design出現(xiàn),管理布局方面十分強(qiáng)大,需要的朋友可以參考下2016-04-04