在开发过程中,经常遇到测试提出的内存增长明显的测试报告或者是测试提出的OOM问题,此时就需要跟测试获取hprof文件对内存增长和内存泄漏等问题进行排查,那么MAT就是我们必须学会的排查内存增长或泄漏等问题的工具
1、生成hprof文件导出
2、打开MAT 导入我们的2个hprof文件
其中1个是旋转多次屏幕之后的文件(属于内存泄漏部分),另1个是没有内存泄漏的文件,通过以下操作打开:Open File->选择文件->Leak Suspects Report->Finish
在打开文件的时候,经常会遇到Parsing heap dump from xxx has encountered a problem. Error opening heap dump xxx.hprof
这个错误,由于MAT是适用于eclipse的版本,需要将导出来的hprof文件转换一下格式,通过Android SDK自带的工具,在命令行中输入
hprof-conv 1.hprof 2.hprof
3、在OverView视图找到Histogram
4、进入Histogram,查看内存使用情况
该视图以Class类的维度展示每个Class类的实例存在的个数、占用的[Shallow内存]和[Retained内存]大小,可以分别排序显示
5、分别在2个hprof文件中做如下动作,将Histogram视图添加到对比栏
6、点击对比
7、通过比较后就会生成一个比较结果表ComPared Tables,我们通过输入我们自己的包名,找到对应的比较结果
并且在上面的可以设置不同的对比方式
8、通过比较发现我们的程序存在内存泄漏,那么下面就要在内存泄漏的文件中找到泄漏的根源
9、回到泄漏的文件中,找到Histogram入口,输入我们发现泄漏的类名
10、通过右键,查看MainActivity实例被哪些对象使用
11、由于使用的对象大多数为系统级别的引用,很难让我们去分辨具体的内存泄漏,所以我们通过遍历GC Root树去将那些有可能被GC回收的实例将他们去除,右键取出可能会被GC的虚/弱/软引用
由于Paths to GC roots是针对单个对象的,故在Histogram视图无法使用,可以在dominator_tree上用
12、最后只剩下我们泄漏的内存
1、Dominator Tree
该视图以实例对象的维度展示当前堆内存中Retained Heap占用最大的对象,以及依赖这些对象存活的对象的树状结构
2、Immediate Dominator
右键选择Immediate Dominator来查看某个对象被谁直接引用
3、Duplicate Classes
该视图列出被加载多次的类,结果按类加载器进行分组,目标是加载同一个类多次被类加载器加载。使用该工具很容易找到部署应用的时候使用了同一个库的多个版本
4、Top Consumers
列出占用总堆内存超过1%的对象
5、Thread Overview
该视图可以看到:线程对象/线程栈信息、线程名、Shallow Heap、Retained Heap、类加载器、是否Daemon线程等信息
6、Group分组
可以选择以另一种分组方式显示(默认是No Grouping(objects),即以对象维度分组)
7、Find Object by address
通过十六进制的地址查找对应的对象
8、OQL(Object Query Language)
类似SQL查询语言,可以过滤一些想要的内存信息
select * from com.example.mat.Listener
select * from java.util.HashMap where size=0 and modCount=0
select * from java.util.Hashtable where count=0 and modCount=0
select * from java.util.ArrayList where size=0 and modCount=0
select * from instanceof android.app.Activity
从工具栏入口可以选择MAT默认提供的一些报告工具,有利于我们分析问题
1、Heap Dump Overview
查看整个堆的概括情况,例如:堆内存大小、对象个数、类的个数、类加载器的个数、GC root的个数、堆内存文件的格式、文件的创建时间、位置等信息
2、Leak Suspects
查看潜在的内存泄漏问题
3、Top Components
针对那些占用堆内存超过整个堆内存1%大小的组件做一系列的分析
1、分析集合大小
分析集合的大小,可以更合理的去初始化集合的大小,达到性能合理利用
2、分析集合填充率
集合填充率是可以更好反映集合在自身大小确定的情况下,是否被完全填充满,推断出哪些集合具有预分配内存能力,填充率 = size / capacity(容量)
3、分析集合碰撞率
集合碰撞率指的是Hash碰撞,通过减少Hash碰撞冲突能优化集合性能,碰撞率 = 碰撞的实体/Hash表中所有实体
4、分析集合键值对
1、在查找内存泄漏问题时
通常内存泄漏发生在IO流,内部类,Handler,Activity,Cursor,Receiver等组件中
Activity字段
快速找到是否存在泄漏的对象select * from instanceof android.app.Activity
并移除所有虚/弱/软引用2、在查找内存增长问题时
通常内存增长的情况有很多种,具体还是得找到怀疑点,看代码逻辑解决
项目包名
,通过Retained Heap排序,快速找到内存占用大的对象,进一步在代码中排查