Android性能測試——發現和定位內存泄露和卡頓

  • 2019 年 12 月 11 日
  • 筆記

來源:http://www.51testing.com

背景介紹

Android用戶也許會經常碰到以下的問題:

  1)應用後台開着,手機很快沒電了——應用耗電大;

  2)首次/非首次啟動應用,進入應用特別慢——應用啟動慢;

  3)應用使用過程中,越來越卡——CPU能力不足/內存泄露;

  4)應用頁面卡頓——幀率較低、頁面卡頓。

  因此,對開發的Android應用,必須對其進行性能測試,不然將會直接影響用戶體驗。

  Android應用性能測試通常包括:啟動時間、內存、CPU、耗電量、流量、流暢度等。我們將在這個月陸續為大家簡單介紹一下每個測試點的常見測試方法及簡單的定位思路,僅供參考。之前兩周內,我們為大家介紹了啟動時間、內存&CPU測試方法,本期我們介紹Android測試的難題——內存泄漏和卡頓。

內存泄露

  內存泄露方面使用MAT工具定位分析。

  準備條件:

  1)手機是開發版room(建議使用小米的開發版room)

  2)手機開啟root權限,可以下載一個root explorer獲取root權限

  操作步驟:

  使用Androidstudio—>tools—>Android Device Monitor->進入DDMS

  1)界面中選出應用程序的包名

  2)點擊Update Heap來更新統計信息(實現界面操作)

  3)開始進行測試,測試結束後,點擊Cause GC

  4)點擊Dump HPROF file,將該應用當前的內存信息保存成hprof文件

  圖1

  如果是用 MATEclipse 插件獲取的 Dump文件,則不需要經過轉換,Adt會自動進行轉換然後打開;如果不是DDMS Dump 出的文件要經過轉換才能被 MAT識別,進入到android sdk提供hprof-conv工具目錄下,(一般位於sdk/platform-tools下)。輸入命令 ./hprof-convxxx-a.hprof xxx-b.hprof進行轉換。

  利用MAT打開轉換後的 hprof文件:

  圖2

  圖3

  Histogram圖表中主要統計了消耗佔比較高的類的實例數量及佔用空間

  Dorminator Tree(支配樹)支配樹可以直觀地反映一個對象的retained heap

 1、Histogram查詢

  用的最多的功能是 Histogram,點擊 Actions下的 Histogram項將得到 Histogram結果,它按類名將所有的實例對象列出來,可以點擊表頭進行排序,在表的第一行可以輸入正則表達式來匹配結果,我們一般查看Activity和Fragment是否有內存泄露,一般Fragmen會有混淆,所以需要QA保留好對應的mapping文件。

  圖4

  2、選中佔用內存最大的Activity->右鍵—>Merge Shortest Path To GC Roots->exclude allphantom/weak/soft etc. references

  Merge Shortest Path To GC Roots 它能夠從當前內存映像中找到一條指定對象所在的到GC Root的最短路徑。這個功能還附帶了其他幾個選項,這幾個選項分別指明了計算最短路徑的時候是否是需要排除弱引用、軟引用及影子引用等,一般來說這三種類型的引用都不會是造成內存泄漏的原因,因為JVM遲早是會回收只存在這三種引用的資源的,所以在dump內存映像之前我們都會手動觸發一次gc,同時在找最短引用路徑的時候也會選擇上exclude all phantom/weak/soft etc. references選項,排除來自這三種引用的干擾。

  3、結果如下圖,由圖可以看出 com.android.org.chromium.android_webview.Aw-

  PasswordHandler @0x42cbee10 組件始終調用com.baidu.next.tieba.reply.activity.

  ReplyDetailActivity @0x42bd52d8這個函數,導致內存泄漏問題。

  圖5

卡頓

  卡頓產生的原因: 1、CPU 資源消耗原因;2、GPU 資源消耗原因。

  CPU上文已經闡述,接下來說一下GPU。一般安卓流暢度測試,關注圖片處理器每秒刷新的幀數(FPS),他用來指示頁面是否平滑的渲染。高的幀率可以得到更流暢,更逼真的動畫,不過幀率達到60fps以上,人眼主觀感受到的差別就不大了。所以以60fps作為衡量標準,即要求每一幀刷新的時間小於16ms,這樣才能保證滑動中平滑的流暢度。

備註:GPU呈現模式用來測量app的幀速率,屬於GPU,Profile工具的一種.目前安卓基礎60fps以滿幀數計算,60fps在一秒沒繪製造成,所以可以計算出1÷60≈1.66(繪製每幀需要的時間約為16ms)

1、GPU呈現模式分析(Peofile GPU Rendering tool)

  測試方法:

  a、點擊Android設備的「設置」->"開發者選項",然後勾選「GPU呈現模式分析」。

  b、打開開發者選項後勾選」GPU呈現模式分析」後選擇「屏幕上顯示為條形圖」這樣可以直觀的看出每個時間點的幀數大小。如下圖:

  圖6

  當你的應用程序在運行時,你會看到一排柱狀圖在屏幕上,從左到右動態地顯示,每一個垂直的柱狀圖代表一幀的渲染,越長的垂直柱狀圖表示這一幀需要渲染的時間越長.隨着需要渲染的幀數越來越多,他們會堆積在一起,這樣你就可以觀察到這段時間幀率的變化。

 參數介紹如下:

  綠色水平線代表16ms,要確保一秒內打到60fps,你需要確保這些幀的每一條線都在綠色的16ms標記線之下.任何時候你看到一個豎線超過了綠色的標記現,你就會看到你的動畫有卡頓現象產生.

  藍色代表測量繪製的時間,或者說它代表需要多長時間去創建和更新你的DisplayList.在Android中,當你看到藍色的線很高的時候,有可能是因為你的一堆視圖突然變得無效了(即需要重新繪製),或者你的幾個自定義視圖的onDraw函數過於複雜.

  紅色代表執行的時間,這部分是Android進行2D渲染 Display List的時間,為了繪製到屏幕上,Android需要使用OpenGl ES的API接口來繪製Display List.這些API有效地將數據發送到GPU,最總在屏幕上顯示出來.

  橙色部分表示的是處理時間,或者說是CPU告訴GPU渲染一幀的時間,這是一個阻塞調用,因為CPU會一直等待GPU發出接到命令的回復,如果柱狀圖很高,那就意味着你給GPU太多的工作,太多的負責視圖需要OpenGL命令去繪製和處理.

  c、如果需要分析具體詳細的數據,需要結合下面的命令來進行,選擇顯示於adb shelldumpsys gfxinfo來使用,然後輸入:adb shell dumpsys gfxinfo"你自己的應用名字" > fps.txt 後,在電腦中找到fps.txt文件,找到"Profile datain ms"的Draw Process Exceute這三列數據,Excel做出表格,sum出每列的總GPU時間,如圖:

  圖7-8

  Draw 對應於藍色線:是消耗在構建java顯示列表DisplayList的時間。說白了就是執行每一個View的onDraw方法,創建或者更新每一個View的DisplayList對象的時間。

  Process 對應於紅色線:是消耗在Android的2D渲染器執行顯示列表的時間。你的視圖層次越多,要執行的繪圖命令就越多。

  Execute 對應於橙色線:是消耗在排列每個發送過來的幀的順序的時間.或者說是CPU告訴GPU渲染一幀的時間,這是一個阻塞調用,因為CPU會一直等待GPU發出接到命令的回復。

 2、FPS Meter測試安卓幀數

  FPSMeter是一款非常實用的小軟件,能夠用數字實時顯示安卓界面的每秒幀數,非常直觀。此外,FPS Meter還可以顯示最大幀數、最小幀數以及平均幀數。由於涉及到了系統功能,所以FPSMeter需要root。如果你打算嘗試,請先root機後再使用。開啟服務後,即可看到有幀數顯示於界面上。這裡要注意,使用FPS Meter測量幀數需要在開發者選項中停用HW疊加層才會比較準確。

  3、在程序種畫一個圓點,計算圓點1秒繪製次數

   貼吧目前記錄FPS值的方法是,在程序中創建僅有一個圓點的view,然後計算該view每秒被繪製的次數。理想值:1秒繪製60次

  4、AndroidStudio 自帶 GPU測功能

   如下圖,AndroidStudio自帶GPU監控功能,縱軸表示每楨繪製的時間,橫軸是運行時間。

  圖9

  上述四種方法就是測試FPS流暢度的常用方法。當QA發現有卡頓問題時,可以從以下幾點着手分析,逐一排查。

  1、內存佔用過多,GC次數高,阻塞主線程;

  2、主線程做了些無關的耗時操作,eg:在滑動過程中打日誌,訪問過多io;

  3、過度渲染,渲染層級太多或者次數太多,導致渲染時間長 eg:滑動過程中,動畫導致整個列表重新繪製;

  4、創建view時,過多的動態創建或者複雜頁面創建時間過長。eg:五樓圖文直播輪播卡片。

歡迎參加眾測:

https://wap.ztestin.com/site/register?usercode=FAAAQwMQGAAXAwQBA3QhExcDHAQDPjVaABMIQg%3D%3D