MAT内存分析工具使用

摘要:Eclipse Memory Analysis Tools (MAT) 是一个分析 Java堆数据的专业工具,用它可以定位内存泄漏的原因。

正文:

Memory Analyzer的安装

  • Eclipse->Help->Eclipse Marketplace
  • 安装完成后可以调用jdk工具jps查看当前的java进程,然后调用jmap将该进程的内存heap输出到文件。
  • 通过MAT以图像形式直观的展示内存泄漏报表等

首先Eclipse->File->Open File 打开上一步生成的文件

第一个选项是内存泄漏报表(自动检查可能存在内存泄露的对象,通过报表展示存活的对象以及为什么他们没有被垃圾收集);

第二个是对象报表(对可疑对象进行分析,如字符串是否定义重了,空的collection、finalizer以及弱引用等);

这里我们打开第一个:

Memory Analyzer主界面介绍

  • 下面的Histogram(列出内存中的对象,对象的个数以及大小)这里我们可以使用正则去进行匹配

可以在具体的Class右键List objects->with incoming…./outgoing…查看该Class的实例

1. outgoing references :表示该对象的出节点(被该对象引用的对象)。
2. incoming references :表示该对象的入节点(引用到该对象的对象)。
  • 下面的Dominator Tree是列出最大的对象以及其依赖存活的Object (大小是以Retained Heap为标准排序的)
  • 而Top Consumers则是通过图形列出最大的Object
  • Duplicate Class是通过MAT自动分析泄漏的原因

一般Histogram和 Dominator Tree是最常用的。

Memory Analyzer中概念介绍

  • Shallow heap

Shallow size就是对象本身占用内存的大小,不包含其引用的对象。

1. 常规对象(非数组)的Shallow size由其成员变量的数量和类型决定。
2. 数组的shallow size由数组元素的类型(对象类型、基本类型)和数组长度决定
  • Retained Heap

它表示如果一个对象被释放,那么因为该对象的释放而减少引用从而导致释放所有的对象所占用的heap大小

为了计算Retained Memory,MAT引入了Dominator Tree。加入对象A引用B和C,B和C又都引用到D(一个菱形)。此时要计算Retained Memory,A的包括A本身和B,C,D。B和C因为共同引用D,所以他俩的Retained Memory都只是他们本身。D当然也只是自己。我觉得是为了加快计算的速度,MAT改变了对象引用图,而转换成一个对象引用树。在这里例子中,树根是A,而B,C,D是他的三个儿子。B,C,D不再有相互关系。把引用图变成引用树,计算Retained Heap就会非常方便,显示也非常方便。对应到MAT UI上,在dominator tree这个view中,显示了每个对象的shallow heap和retained heap。然后可以以该节点位树根,一步步的细化看看retained heap到底是用在什么地方了。要说一下的是,这种从图到树的转换确实方便了内存分析,但有时候会让人有些疑惑。本来对象B是对象A的一个成员,但因为B还被C引用,所以B在树中并不在A下面,而很可能是平级,如下图所示。

为了纠正这点,MAT中点击右键,可以List objects中选择with outgoing references和with incoming references。这是个真正的引用图的概念

  • GC Root

GC发现通过任何reference chain(引用链)无法访问某个对象的时候,该对象即被回收。名词GC Roots正是分析这一过程的起点,例如JVM自己确保了对象的可到达性(那么JVM就是GC Roots),所以GC Roots就是这样在内存中保持对象可到达性的,一旦不可到达,即被回收。通常GC Roots是一个在current thread(当前线程)的call stack(调用栈)上的对象(例如方法参数和局部变量),或者是线程自身或者是system class loader(系统类加载器)加载的类以及native code(本地代码)保留的活动对象。所以GC Roots是分析对象为何还存活于内存中的利器。

在Histogram或者Domiantor Tree的某一个条目上,右键可以查看其GC Root Path

参考:

http://blog.csdn.net/yxz329130952/article/details/50288145

http://www.jianshu.com/p/d8e247b1e7b2

晚安~

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏专注 Java 基础分享

虚拟机类加载机制

虚拟机把字节码文件从磁盘加载进内存的这个过程,我们可以粗糙的称之为「类加载」,因为「类加载」不仅仅是读取一段字节码文件那么简单,虚拟机还要进行必要的「验证」、「...

4697
来自专栏Java技术栈

Java内存泄漏介绍

内存管理是Java最重要的优势之一,你只需创建对象,Java垃圾收集器会自动负责分配和释放内存。但是,情况并不那么简单,因为在Java应用程序中经常发生内存泄漏...

3827
来自专栏IT可乐

JVM 运行时的内存分配

  首先我们必须要知道的是 Java 是跨平台的。而它之所以跨平台就是因为 JVM 不是跨平台的。JVM 建立了 Java 程序和操作系统之间的桥梁,JVM 是...

2068
来自专栏WindCoder

JVM-Java内存区域

JVM在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域,都有着各自的用途以及创建和销毁时间。包括以下几个如图所示的运行时数据区域:

1951
来自专栏欧阳大哥的轮子

深入解构iOS系统下的全局对象和初始化函数

事件源于接入了一个第三方库导致应用出现了大量的crash记录,很奇怪的是这么多的crash居然没有收到用户的反馈信息! 在这个过程中每个崩溃栈的信息都明确的指向...

2062
来自专栏温安适的blog

手写jvm中的各种OOM

3809
来自专栏微信公众号:Java团长

Java虚拟机工作原理

首先我想从宏观上介绍一下Java虚拟机的工作原理。从最初的我们编写的Java源文件(.java文件)是如何一步步执行的,如下图所示,首先Java源文件经过前端编...

1162
来自专栏韩伟的专栏

框架设计原则和规范(完)

祝大家圣诞节快乐!有事没事别出门,外面太!挤!了! 此文是《.NET:框架设计原则、规范》的读书笔记,本文内容较多,共分九章,今天推送最后一章。 1. 什么是好...

2884
来自专栏java一日一条

【Java并发编程】使用wait/notify/notifyAll实现线程间通信的几点重要说明

在 Java中,可以通过配合调用Object对象的wait()方法和notify()方法或notifyAll()方法来实现线程间的通信。在线程中调用 wait(...

913
来自专栏纯洁的微笑

jvm系列(一):java类的加载机制

1、什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个 java.lang.Cl...

3906

扫码关注云+社区

领取腾讯云代金券