Android記憶體測試方法梳理和實現原理簡析

maweiliang發表於2017-12-22

廢話不說,直接上乾貨。

1:程式碼的方式

程式碼中使用Debug的getMemoryInfo(Debug.MemoryInfo memoryInfo)或ActivityManager的MemoryInfo[] getProcessMemoryInfo(int[] pids)

ActivityManager mAm = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
Debug.MemoryInfo[] memoryInfoArray = mAm.getProcessMemoryInfo(pids);
複製程式碼

MemoryInfo物件中可以看看詳細的記憶體資訊,欄位如下: 目前很多記憶體測試工具都是採用這種方式,如哆啦A夢、GT等。這種方式簡單方便

2:dumpsys 命令

adb shell dumpsys meminfo package_name|pid
複製程式碼

一般關注關PSS列的這幾個欄位:

  • Native Heap:JNI層的記憶體
  • Dalvik Heap:Java層的記憶體分配情況
  • Total PSS :應用真正佔據的記憶體大小

一般公司測試都是會採用這種方式獲取記憶體資料的

3:smaps檔案

Linux在2.6版本之後有一個proc偽檔案,在它下面記錄各種資訊,其中在proc/pid/smaps記錄某個pid的內,smaps記錄記憶體詳細的使用情況。使用下面的命令可以讀檔案的值

cat /proc/pid/smaps
複製程式碼

檔案格式如下:

Android記憶體測試方法梳理和實現原理簡析
檔案欄位意義:

  • 400ca000-400cb000:本段虛擬記憶體的地址範圍
  • r-xp :檔案許可權,r(讀)、w(寫)、x(執行)、p表示私有,s代表共享,如果不具有哪項許可權用"-"代替
  • 00000000 :對映檔案的偏移量
  • b3:11 :檔案裝置號
  • 1345 :被對映到虛擬記憶體檔案的映索節點
  • /system/lib/libplddbgutil.so:檔名稱
  • Size:相應虛擬地址空間的大小
  • RSS: 正在使用的實體記憶體的大小
  • Shared_Clean: Rss中和其他程式共享的未使用頁數
  • Shared_Dirty: Rss和其他程式共享已經使用的頁數
  • Private_Clean: Rss私有區域未使用的頁數
  • Private_Dirty: Rss私有區域已經使用的頁數

smaps檔案一般有啥作用呢,譬如我們通過dumpsys meminfo 獲取記憶體時,發現某一項記憶體資料異常,想弄清楚資料都是有哪些檔案產生,我們就可以通過讀取smaps詳細排查。

4:原始碼分析

我們執行dumpsys memInfo 命令後的程式碼執行流程是怎樣的呢,dumpsys命令會根據傳進來的引數通過函式checkService來找到具體的service, 然後執行該service的dump方法,最總達到dump service的目的。

那我們傳進入的memInfo對應的是哪個service呢,這個我們需要檢視ActivityManagerService.Java類,搜尋一下memInfo,最後我們發現它對應的service是MemBinder。

image

我們點選MemBinder類看類內部的實現

image

方法內部首先會進行android.Manifest.permission.DUMP許可權檢查,最終呼叫 dumpApplicationMemoryUsage方法,我們再看dumpApplicationMemoryUsage方法做了哪些操作

image

這個方法內容比較多,這裡我們只顯示了它最終調的地方,我們最終發現最後會呼叫android.os.Debug.java類。

image

其實會呼叫android.os.Debug.java類呼叫了大量的Native方法實現的,android.os.Debug.java對應的native檔案是android_os_Debug.cpp,上面的Debug.getMemoryInfo(pid, mi)實際上最後呼叫了 android_os_Debug.cpp的android_os_Debug_getDirtyPagesPid方法

image

android_os_Debug_getDirtyPagesPid方法呼叫了load_maps(int pid, stats_t* stats)方法

image

load_maps中是通過讀取smaps檔案內容,到此dumpsys memInfo的實現就非常清晰了。

第一種程式碼的實現方式,其實最後走的流程和上面的是一樣的。

android_os_Debug.cpp地址: android_os_Debug.cpp檔案

5:記憶體測試關注的點

1.記憶體是否持續上漲:進入某項功能記憶體增長,退出功能時記憶體是否下降

2.是否頻繁的GC:頻繁的gc可能是因為你的程式記憶體碎片導致的,這也是需要優化的一個方向

3.記憶體的峰值是否在單個應用允許的最大值之內

相關文章