adb 命令
使用android shell命令查看內存使用情況
單位爲千字節 KB
adb shell dumpsys meminfo pkgname
示例
adb shell dumpsys meminfo top.ftas.demo.leaked
# 查看 Java Heap 大小
adb shell dumpsys meminfo top.ftas.demo.leaked|grep Java\ Heap
# 查看 Native Heap 大小
adb shell dumpsys meminfo top.ftas.demo.leaked|grep Native\ Heap
內存動態監控
watch -n 0.5 adb shell dumpsys meminfo top.ftas.demo.leaked
一般需要重點關注下面:
Heap Alloc 列,TOTAL 行(或者 App Summary 的 Java Heap ) - 數值的大小
Activities - 數值的大小
Views - 數值的大小
AppContexts - 數值的大小
通過快速輸出 Activities 的數量,檢查出是否有 Activities 泄露
adb shell dumpsys meminfo 應用包名 |grep Activities
示例
adb shell dumpsys meminfo top.ftas.demo.leaked |grep Activities
AppContexts: 11 Activities: 8
AppContexts: 12 Activities: 9
快速獲取當前 Activity ,確定泄露位置
adb shell dumpsys activity activities | sed -En -e '/Running activities/,/Run #0/p'
在當前進程中抓取當前進程的hprof信息
adb shell am dumpheap pid或者pkgName file
獲取 pid 命令
adb shell ps | grep pkgName
示例
#獲取 pid
adb shell ps |grep top.ftas.demo.leake
#生成 hprof
adb shell am dumpheap 9686 /data/local/tmp/test-leaked-pid.hprof
#生成 hprof
adb shell am dumpheap top.ftas.demo.leaked /data/local/tmp/test-leaked-pkg.hprof
#下載 hprof
adb pull /data/local/tmp/test-leaked-pkg.hprof
#hprof 轉成 mat 識別的格式
hprof-conv test-leaked-pkg.hprof test-leaked-pkg.mat.hprof
u0_a876 9686 782 1785284 98684 SyS_epoll_ 0000000000 S top.ftas.demo.leaked
在當前進程使用 Debug.dumpHprofData 獲取 hprof 文件
Debug.dumpHprofData(path);
android-developer-dumpHprofData
示例:
File hprofFile = new File(getExternalCacheDir(), "DumpHprofDataActivity-dumpHprofData.hprof");
String path = hprofFile.getAbsolutePath();
Log.e("DumpHprofDataActivity", "hprofFile.getAbsolutePath = " + path);
try {
Debug.dumpHprofData(path);
} catch (IOException e) {
Log.e("DumpHprofDataActivity", Log.getStackTraceString(e));
}
#從緩存中拉取 hprof 文件
adb pull /storage/emulated/0/Android/data/top.ftas.demo.leaked/cache/DumpHprofDataActivity-dumpHprofData.hprof
#hprof 文件格式轉換
hprof-conv DumpHprofDataActivity-dumpHprofData.hprof DumpHprofDataActivity-dumpHprofData.mat.hpro
jhat
分析java堆的命令,可以將堆中的對象以html的形式顯示出來,包括對象的數量,大小等等,並支持對象查詢語言
# 生成 hprof
adb shell am dumpheap top.ftas.demo.leaked /data/local/tmp/test-leaked-pkg.hprof
# 下載 hprof
adb pull /data/local/tmp/test-leaked-pkg.hprof
# 將 HPROF 文件從 Android 格式轉換爲 Java SE HPROF 格式
hprof-conv test-leaked-pkg.hprof test-leaked-pkg.mat.hprof
# 啓動 jhat 服務器,分析 hprof 文件
# 或 jhat -J-Xmx512m <heap dump file>
jhat test-leaked-pkg.mat.hprof
# 訪問本地 jhat 站點
open http://localhost:7000/
分析內存泄露常見思路
mat 分析 - Histogram - Activity 泄露
進入 Histogram
Class Name 中輸入 Activity 進行過濾
點擊 Objects 排序
重點關注 Objects 字段, 哪些 Activity 過多
找到 Objects 大於 1 的,一般就有泄露的可能
右鍵有泄露可能的 Activity,按如下方式確定泄露路徑
Merge Shortes Paths to GC Roots
exclude all phantom/weak/soft etc.references
其中最下方的 Total:7 entries 是總泄露數
依次展開任意一行,可以看到完整的泄露路徑。其中最頂部是 GC Root。
mat 分析 - Histogram - Shallow Heap 排序
一般佔比最高的是 byte[] 或者 char[]
右鍵 byte 數組
Merge Shortes Paths to GC Roots
exclude all phantom/weak/soft etc.references
按 Ref.Shallow Heap 排序,確認 Ref.Shallow Heap 佔用內存較多的對象是否合理
Android Studio Profiler - Memory Profiler Activity 內存泄露分析法
先捕獲堆轉儲,請點擊 Memory Profiler 工具欄中的 Dump Java heap 圖標
Filter 中輸入 Activity 回車
點擊 Allocations 按實例數排序
點擊 Allocations 數值較多的 Activity
右側 『Instance View』面板中會出現所有實例對象(觀察 Depth,比如爲 5),點擊任意一個實例對象
右下側『References』兩板中會出現引用鏈
依次展開『References』,找到泄露源。特別注意,由於有循環引用,這裏一定要按照 Depth 『5 4 3 2 1 0』的順序展開。否則會無限循環,無窮盡也。
CPU Profiler