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