Android进阶——性能优化之MAT的使用

前言

在开发过程中,经常遇到测试提出的内存增长明显的测试报告或者是测试提出的OOM问题,此时就需要跟测试获取hprof文件对内存增长和内存泄漏等问题进行排查,那么MAT就是我们必须学会的排查内存增长或泄漏等问题的工具

概念

  • MAT:MemoryAnalyzer,内存的分析工具,通过工具可以分析堆内存的使用情况和检测内存泄漏等问题
  • hprof文件:指的是当前Android堆内存的快照情况,当前设备的堆内存会全部保存在hporf中,可以通过MAT工具进行打开

分析内存

1、生成hprof文件导出

Android进阶——性能优化之MAT的使用_第1张图片

2、打开MAT 导入我们的2个hprof文件

其中1个是旋转多次屏幕之后的文件(属于内存泄漏部分),另1个是没有内存泄漏的文件,通过以下操作打开:Open File->选择文件->Leak Suspects Report->Finish

Android进阶——性能优化之MAT的使用_第2张图片

在打开文件的时候,经常会遇到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

Android进阶——性能优化之MAT的使用_第3张图片

4、进入Histogram,查看内存使用情况

该视图以Class类的维度展示每个Class类的实例存在的个数、占用的[Shallow内存]和[Retained内存]大小,可以分别排序显示

  • Objects:当前Class的实例存在的个数
  • Shallow内存:代表当前类所有实例所占用的内存大小
  • Retained内存:代表从该类实例沿着reference chain往下所能收集到的其他类实例的Shallow Heap(Size)总和

Android进阶——性能优化之MAT的使用_第4张图片

5、分别在2个hprof文件中做如下动作,将Histogram视图添加到对比栏

Android进阶——性能优化之MAT的使用_第5张图片

6、点击对比

这里写图片描述

7、通过比较后就会生成一个比较结果表ComPared Tables,我们通过输入我们自己的包名,找到对应的比较结果

Android进阶——性能优化之MAT的使用_第6张图片

并且在上面的可以设置不同的对比方式

Android进阶——性能优化之MAT的使用_第7张图片

8、通过比较发现我们的程序存在内存泄漏,那么下面就要在内存泄漏的文件中找到泄漏的根源

Android进阶——性能优化之MAT的使用_第8张图片

9、回到泄漏的文件中,找到Histogram入口,输入我们发现泄漏的类名

Android进阶——性能优化之MAT的使用_第9张图片

10、通过右键,查看MainActivity实例被哪些对象使用

Android进阶——性能优化之MAT的使用_第10张图片

  • with outgoing references:查看当前对象持有的外部对象引用,从箭头可以看出,当前对象下面还有谁
  • with incoming references:查看当前对象被哪些外部对象所引用,从箭头可以看出,当前对象上头还有谁

Android进阶——性能优化之MAT的使用_第11张图片

Android进阶——性能优化之MAT的使用_第12张图片

11、由于使用的对象大多数为系统级别的引用,很难让我们去分辨具体的内存泄漏,所以我们通过遍历GC Root树去将那些有可能被GC回收的实例将他们去除,右键取出可能会被GC的虚/弱/软引用

  • Paths to GC Roots:从当前对象到GC roots的调用链,这个调用链解释了为什么当前对象还能存活
  • Merge Shortest Paths to GC roots:从GC roots到一个或一组对象的调用树

由于Paths to GC roots是针对单个对象的,故在Histogram视图无法使用,可以在dominator_tree上用

Android进阶——性能优化之MAT的使用_第13张图片

12、最后只剩下我们泄漏的内存

Android进阶——性能优化之MAT的使用_第14张图片

常用用法

1、Dominator Tree

该视图以实例对象的维度展示当前堆内存中Retained Heap占用最大的对象,以及依赖这些对象存活的对象的树状结构

Android进阶——性能优化之MAT的使用_第15张图片

2、Immediate Dominator

右键选择Immediate Dominator来查看某个对象被谁直接引用

3、Duplicate Classes

该视图列出被加载多次的类,结果按类加载器进行分组,目标是加载同一个类多次被类加载器加载。使用该工具很容易找到部署应用的时候使用了同一个库的多个版本

Android进阶——性能优化之MAT的使用_第16张图片

4、Top Consumers

列出占用总堆内存超过1%的对象

Android进阶——性能优化之MAT的使用_第17张图片

5、Thread Overview

该视图可以看到:线程对象/线程栈信息、线程名、Shallow Heap、Retained Heap、类加载器、是否Daemon线程等信息

Android进阶——性能优化之MAT的使用_第18张图片

6、Group分组

可以选择以另一种分组方式显示(默认是No Grouping(objects),即以对象维度分组)

Android进阶——性能优化之MAT的使用_第19张图片

7、Find Object by address

通过十六进制的地址查找对应的对象

Android进阶——性能优化之MAT的使用_第20张图片

8、OQL(Object Query Language)

类似SQL查询语言,可以过滤一些想要的内存信息

Android进阶——性能优化之MAT的使用_第21张图片

  • 查找包名
select * from com.example.mat.Listener
  • 查找size=0并且未使用过的集合
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
  • 查找所有的Activity
select * from instanceof android.app.Activity

分析报告

从工具栏入口可以选择MAT默认提供的一些报告工具,有利于我们分析问题

Android进阶——性能优化之MAT的使用_第22张图片

1、Heap Dump Overview

查看整个堆的概括情况,例如:堆内存大小、对象个数、类的个数、类加载器的个数、GC root的个数、堆内存文件的格式、文件的创建时间、位置等信息

Android进阶——性能优化之MAT的使用_第23张图片

2、Leak Suspects

查看潜在的内存泄漏问题

Android进阶——性能优化之MAT的使用_第24张图片

3、Top Components

针对那些占用堆内存超过整个堆内存1%大小的组件做一系列的分析

Android进阶——性能优化之MAT的使用_第25张图片

分析集合

1、分析集合大小

分析集合的大小,可以更合理的去初始化集合的大小,达到性能合理利用

  • 筛选目标对象

Android进阶——性能优化之MAT的使用_第26张图片

  • 查找被回收时那些将被GC回收的对象集合

Android进阶——性能优化之MAT的使用_第27张图片

  • 筛选指定的Object(Hash Map,ArrayList)并按照集合大小进行分组

Android进阶——性能优化之MAT的使用_第28张图片

  • 查看哪个对象正在引用当前大小为0的集合

Android进阶——性能优化之MAT的使用_第29张图片

2、分析集合填充率

集合填充率是可以更好反映集合在自身大小确定的情况下,是否被完全填充满,推断出哪些集合具有预分配内存能力,填充率 = size / capacity(容量)

  • Collections fill ratio

Android进阶——性能优化之MAT的使用_第30张图片

  • 查看填充率

Android进阶——性能优化之MAT的使用_第31张图片

3、分析集合碰撞率

集合碰撞率指的是Hash碰撞,通过减少Hash碰撞冲突能优化集合性能,碰撞率 = 碰撞的实体/Hash表中所有实体

  • Map Collision Ratio

Android进阶——性能优化之MAT的使用_第32张图片

  • Immediate dominators

Android进阶——性能优化之MAT的使用_第33张图片

4、分析集合键值对

  • Hash Entries查看key value

Android进阶——性能优化之MAT的使用_第34张图片

经验总结

1、在查找内存泄漏问题时

通常内存泄漏发生在IO流,内部类,Handler,Activity,Cursor,Receiver等组件中

  • 如果是怀疑Activity组件泄漏的时候,可以使用Dominator Tree功能,优先过滤Activity字段快速找到是否存在泄漏的对象
  • 如果是怀疑Activity组件泄漏的时候,可以通过OQLselect * from instanceof android.app.Activity并移除所有虚/弱/软引用

2、在查找内存增长问题时

通常内存增长的情况有很多种,具体还是得找到怀疑点,看代码逻辑解决

  • 可以使用Leak Suspects Report功能,查看工具分析出来的内存占用情况,优先分析报告中提出来的问题
  • 可以使用Dominator Tree功能,过滤项目包名,通过Retained Heap排序,快速找到内存占用大的对象,进一步在代码中排查

你可能感兴趣的:(Android进阶——性能优化之MAT的使用)