MAT(Memory Analyzer Tool)
基本概述
- Java堆内存分析器,可以用于查找内存泄漏以及查看内存消耗情况
- MAT是基于Eclipse开发的,不仅可以单独使用,还能以插件方式嵌入Eclipse中使用,是一款免费的性能分析工具
获取堆dump文件
- dump文件内容
- MAT可以分析heap dump文件,在进行内存分析时,只要获得了反映当前设备内存映像的hprof文件,通过MAT打开就能直观地看到当前的内存信息
- 这些内存信息包含
- 所有的对象信息,包括对象实例,成员变量,存储于栈中的基本数据类型值和存储于堆中的其他对象的引用值
- 所有的类信息,包括classloader、类名称、父类、静态变量等
- GCRoot到所有的这些对象的引用路径
- 线程信息,包括线程的调用栈及此线程的线程局部变量(TLS)
- 获取dump文件
- 通过jmap工具生成,可以生成任意一个java进程的dump文件
C:\Users\Administrator\IdeaProjects\jvm>jmap -dump:format=b,file=d:\mat\a.hprof 11896
Dumping heap to D:\mat\a.hprof ...
Heap dump file created
- 通过配置JVM参数生成
- 选项-XX:+HeapDumpOnOutOfMemoryError 或 -XX:+HeapDumpBeforeFullGC
- 选项 -XX:HeapDumpPath所代表的含义就是当程序出现OOM时,将会在相应目录下生成一份dump文件,如果不指定,则在当前目录生成dump文件
- 生产环境中几乎不可能在线对其进行分析,都采用离线分析,因此使用jmap+MAT工具分析dump文件
- 使用VisualVM可以导出堆dump文件
- 使用MAT直接从活动Java程序中导出堆快照
分析堆dump文件
- histogram(直方图):展示了各个类的实例数目以及这些实例的shallow heap或retainedheap的总和
- thread overview
- 查看系统中的Java线程
- 查看局部变量的信息
- 获取对象相互引用的关系
-
with outgoing references
-
with incoming references
-
- 浅堆与深堆
- shallow heap(浅堆)
- 浅堆是指一个对象所消耗的内存,在32位系统中,一个对象引用会占用4个字节,一个int类型会占据4个字节,long型变量占据8字节,每个对象头需要占用8个字节,根据堆快照格式不同,对象的大小可能会向8字节对齐
- 以String为例:2个int值共占用8个字节,对象引用占用4个字节,对象头8字节,合计20字节,向8字节对齐,故占24字节,这24字节为String对象的浅堆大小,它与String的value实际值无关,无论字符串长度如何,浅堆大小始终是24字节
- retained heap(深堆)
- 保留集(Retained Set):对象A的保留集指当对象A被垃圾回收后,可以被释放的所有对象集合(包括对象A本身),即对象A的保留集可以被认为是只能通过对象A被直接或间接访问到的所有对象的集合,指仅被对象A所持有的对象的集合
- 深堆:指对象的保留集中所有的对象的浅堆大小之和
- 注:浅堆指对象本身所占用的内存,不包含其内部引用对象的大小,一个对象的深堆指只能通过该访问到的(直接或间接)所有对象的浅堆之和,即对象被回收,可以释放真实空间
- 对象实际大小
- 对象的实际大小定义为一个对象所能触及的所有对象的浅堆大小之和,也就是对象的大小,与深堆相比,这个在日常开发中更为直观和被人接受,但实际这个概念与垃圾回收无关
- 对象的实际大小定义为一个对象所能触及的所有对象的浅堆大小之和,也就是对象的大小,与深堆相比,这个在日常开发中更为直观和被人接受,但实际这个概念与垃圾回收无关
- shallow heap(浅堆)
- 支配树(Dominator Tree)
- MAT提供了一个称为支配树的对象图,支配树体现了对象实例间的支配关系。在对象引用图中,所有指向对象B的路径都经过A,则认为对象A支配对象B,如果对象A是离对象B最近的一个支配对象,则认为对象A为对象B的直接支配者,支配树是基于对象间的引用图所建立的,它有以下基本特性
- 对象A的子树表示对象A的保留集,即深堆
- 如果对象A支配对象B,那么对象A的直接支配者也支配对象B
- 支配树的边与对象引用图的边不直接对应
- 下图中,左图表示对象引用图,右图表示左图所对应的支配树,对换A,B由根对象直接支配,由于在到对象C的路径中,可以经过A,也可以经过B,因此对象C的直接支配者也是根对象,对象F与对象D相互引用,因为到对象F的所有路径必然经过对象D,因此,对象D是对象F的直接支配者,而到对象D的所有路径中,必须经过C,即从对象F到对象D的引用,从根节点出发,也是经过对象C的,所以,对象D的直接支配者为对象C,同理,对象E支配对象G,到达对象H可以通过对象D,也可以通过对象E,因此对象D和E都不能支配对象H,而经过对象C既可到达D也可到达E,因此对象C为对象H的直接支配者
- MAT提供了一个称为支配树的对象图,支配树体现了对象实例间的支配关系。在对象引用图中,所有指向对象B的路径都经过A,则认为对象A支配对象B,如果对象A是离对象B最近的一个支配对象,则认为对象A为对象B的直接支配者,支配树是基于对象间的引用图所建立的,它有以下基本特性
OQL(Object Query Language)
- MAT支持一种类似于SQL的查询语言OQL(Object Query Language),OQL使用类SQL语法,可以在堆中进行对象的查找和筛选
- SELECT子句
-
在MAT中,Select子句的格式与SQL基本一致,用于指定要显示的列,Select子句中可以使用*,查看结果对象的引用实例(相当于outgoing references)。
-
SELECT * FROM java.util.Vector v
-
使用OBJECTS关键字,可以将返回结果集中的项以对象的形式显示
-
SELECT objects v.elementData FROM java.util.Vector v || SELECT OBJECTS s.value FROM java.lang.String s
-
在Select子句中,使用AS RETAINED SET关键字可以得到所得对象的保留集
-
SELECT AS RETAINED SET * FROM com.chapter11.Student
-
DISTINCT关键字用于在结果集中去除重复对象
-
SELECT DISTINCT OBJECTS classof(s) FROM java.lang.String s
-
- FROM子句
- From子句用于指定查询范围,它可以指定类名、正则表达式或者对象地址
- WHERE子句
- where子句用于指定OQL的查询条件,OQL查询将只返回满足where子句指定条件的对象
- where支持多个条件AND、OR运算
- 内置对象与方法
- OQL可以访问堆内对象的属性,也可以访问堆内代理对象的属性,访问堆内对象的属性时格式:[.]..
- 其中alias为对象名称