Monkey OOM 定位与解决-ADB dumpheap和MAT工具

最近工作中经常遇到Monkey场景中的OOM,终于摆脱忽悠测试有方法可以正常定位到问题了。

总结起来也很简单,就是两步

1.通过脚本定时抓取内存文件
2.通过MAT工具分析内存文件

1.通过ADB 命令抓取内存文件

// 查询包名对应的进程id
adb shell "pidof packagename"
// 通过进程id生成hprof内存快照在手机目录
adb shell am dumpheap 进程ID /data/local/tmp/内存快照名称.hprof
// 将内存文件pull至电脑
adb pull /data/loacl/tmp/内存快照名称.hprof 内存快照名称.hprof

获得文件后我们直接拖入AndroidSutdo即可进行分析

hprof通过AS查看.png

2.通过MAT工具检查当前内存文件中的内存占用

但是OOM时dump出来的文件大小都非常的大,AS在查看的大型内存快照文件时会直接卡住。我们还需要借助MAT工具来帮助分析问题。

MAT Memory AnalyzerTool 是Eclipse项目里面用来分析java内存文件的一个工具
下载地址:https://www.eclipse.org/mat/downloads.php
通过adb命令导出的hprof文件可以在AndroidStudio中直接打开但不能在MAT中直接打开
需要借助sdk/platform-tools/hprof-conv.exe转换后才可以打开

\Android\Sdk\platform-tools\hprof-conv.exe  practiceproject.hprof practiceproject-mat.hprof

打开后就可以看到页面内存分析的页面了


MAT初次打开页面.png

Shallow Heap 与Retained Heap

Shallow Heap浅堆:指的是对象自身所占据的内存,不包含其内部引用对象的大小。

Retained Heap深堆:只能通过该对象访问到的(直接或者间接)所有对象的浅堆之和,即当对象不再被引用时,垃圾回收器所能回收的总内存,包括对象自身所占据的内存,以及仅能够通过该对象引用到的其他对象所占据的内存。
如果A引用了C+D,B引用了C+E。那么A对象的深堆是A+D,同理B的深堆大小是B+E。


ShallowHeap与RetainedHeap.png

histogram 直方图

MAT 的直方图和jmap的-histo子命令一样,都能够展示各个类的实例数目以及这些实例的 Shallow heap 总和。但是,MAT 的直方图还能够计算 Retained heap,并支持基于实例数目或 Retained heap 的排序方式(默认为 Shallow heap)。

总的来说hitstogram适合去检查当前内存中哪些类的占用比例最高。

dominator tree 支配树

在 A支配 B,且 A 不同于 B 的情况下(即 A严格支配 B),如果从 A节点到 B 节点的所有路径中不存在支配 B 的其他节点,那么 A直接支配(immediate dominate)B。这里的支配树指的便是由节点的直接支配节点所组成的树状结构。

由于支配树有唯一使用的特点,使用支配树定位内存泄漏路径很方便。

outgoing和incoming

出引用(当前对象引用的外部对象)和入引用(引用当前对象的对象)

使用MAT定位安卓内存泄漏

这里我们简单使用一个例子

class LeakHolder private constructor() {
 private var activity: Activity? = null
 fun setActivity(activity: Activity?) {
 this.activity = activity
 }

 companion object {
 val instance = LeakHolder()
 }
}

class SecondActivity : AppCompatActivity() {
 override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 setContentView(R.layout.activity_secend)
 LeakHolder.instance.setActivity(this)
 }
}

将SecondActivity交给单例LeakHolder强引用,引用关系LeakHolder -> SecondActivity
在MAT中搜所泄漏的SecondActivity右键选择Merge shortest path to GC Roots 再选择 excluede all xxxx

找到内存泄漏路径.png

MAT就会帮助找到该对象的GC的路径分析路径即可找到内存泄漏的原因
找到内存泄露的原因.png

参考资料:
MemoryAnalyze(MAT)的使用 https://juejin.cn/post/6858981566405771277

你可能感兴趣的:(Monkey OOM 定位与解决-ADB dumpheap和MAT工具)