来源:  https://sourl.cn/ggYpYX

前言

Eclipse Memory Analyzer Tool(MAT)是一个强大的基于Eclipse的内存分析工具,可以帮助我们找到内存泄露,减少内存消耗。

工作中经常会遇到一些内存溢出、内存泄露等问题,同时还可能导致CPU使用率也很高,因为在频繁的进行GC垃圾回收,这时候就需要分析导致问题的原因,MAT是一个比较好用的工具,故在此总结一下个人觉得比较有用的一些MAT相关概念。

 1、Overview

通过 File > Open Heap Dump... 打开dump文件,最先展示就是Overview概述界面,可以对Heap Dump有一个大致的了解,并提供了一些视图、报告的入口,这些视图、报告都对分析Heap Dump很有帮助,后续会介绍。鼠标移动到饼图某个区域上方,在左侧会看到对象的详细信息,如左上方的 Inspector 展示了如:对象hashcode、类名、包名、Class类对象、父类、类加载器、shallow size、retained size、GC root类型。左下方展示了对象的一些属性信息、类层级信息。 2、Histogram视图 以下方式可以打开Histogram柱状图:(1)点击Overview页面Actions区域内的“Histogram视图”链接

(2)点击工具栏的“histogram按钮”

Histogram视图:

该视图以Class类的维度展示每个Class类的实例存在的个数、 占用的 [Shallow内存] 和 [Retained内存] 大小,可以分别排序显示。从Histogram视图可以看出,哪个Class类的对象实例数量比较多,以及占用的内存比较大,Shallow Heap与Retained Heap的区别会在后面的概念介绍中说明。不过,多数情况下,在Histogram视图看到实例对象数量比较多的类都是一些基础类型,如char[](因为其构成了String)、String、byte[],所以仅从这些是无法判断出具体导致内存泄露的类或者方法的,可以使用 List objects 或 Merge Shortest Paths to GC roots 等功能继续钻取数据。如果Histogram视图展示的数量多的实例对象不是基础类型,是有嫌疑的某个类,如项目代码中的bean类型,那么就要重点关注了。 3、Dominator Tree(支配树)视图 以下方式可以打开Dominator Tree视图:(1)点击Overview页面Actions区域内的“Dominator Tree视图”链接

(2)点击工具栏的“Dominator Tree按钮” ,为整个堆打开一个支配树视图

Dominator Tree(支配树)视图:

该视图以实例对象的维度展示当前堆内存中Retained Heap占用最大的对象,以及依赖这些对象存活的对象的树状结构视图中展示了实例对象名、Shallow Heap大小、Retained Heap大小、以及当前对象的Retained Heap在整个堆中的占比点开Dominator Tree实例对象左侧的“+”,会展示出下一层(next level),当所有引用了当前实例对象的引用都被清除后,下一层列出的objects就会被垃圾回收这也阐明了“支配”的含义:父节点的回收会导致子节点也被回收,即因为父节点的存在使得子节点存活Dominator Tree支配树可以很方便的找出占用Retained Heap内存最多的几个对象,并表示出某些objects的是因为哪些objects的原因而存活,在之后的 Dominator Tree概念 部分会对支配树做更详细的说明和举例 4、Group分组功能

使用Group分组功能的方法是,在 Histogram视图 和 Domiantor Tree视图时,点击工具栏的 Group result by...

可以选择以另一种分组方式显示(默认是No Grouping(objects),即以对象维度分组)例如在Histogram视图 或 Dominator Tree视图,选择Group by package,可以更好地查看具体是哪个包里的类占用内存大,也很容易定位到自己的应用程序 5、Thread Overview

Thread视图的入口,在工具栏上:

Thread Overview:

在Thread Overview视图可以看到:线程对象/线程栈信息、线程名、Shallow Heap、Retained Heap、类加载器、是否Daemon线程等信息在分析内存Dump的MAT中还可以看到线程栈信息,这本身就是一个强大的功能,类似于jstack命令的效果而且还能结合内存Dump分析,看到线程栈帧中的本地变量,在左下方的对象属性区域还能看到本地变量的属性,真的很方便

public class TestThreadOverview {    private String str1 = "str1";    private String str2 = "str2";    public static void main(String[] args) {        TestThreadOverview test = new TestThreadOverview();        String local_str = "local_str";        LockSupport.park();    }}

在上面代码的Heap Dump分析中,可以看到线程调用栈的信息,以及main线程的 本地变量TestThreadOverview 和 字符串local_str 的信息

上图中第一个框起来的部分是 new TestThreadOverview()对象(代码第6行),TestThreadOverview对象有两个属性str1、str2第二个框起来的部分是main方法中的字符串变量local_str(代码第8行)结合左侧的对象属性区域,可以更方便的看清线程中对象的具体情况

 6、List objects 在 Histogram 或 Dominator Tree视图,想要看某个条目(对象/类)的引用关系图,可以使用 List objects 功能(1)选择一个条目后,点击工具栏的 Query Browser > List objects,选择 with outgoing references 或 with incoming references

(2)直接在某个条目上点击右键,也可以选择到List object

查看当前对象持有的外部对象引用(在对象关系图中为从当前对象指向外的箭头)

查看当前对象被哪些外部对象所引用(在对象关系图中为指向当前对象的箭头)

例如上面Thread Overview的例子代码中,查看main方法中第6行中的

TestThreadOverview test = new TestThreadOverview();

outgoing references查询结果为:

可以看到TestThreadOverview对象存在3个引用,第一个是TestThreadOverview的Class类对象,因为所有Java类都继承自java.lang.Object,所以都有class对象的引用,后两个是成员变量str1、str2即列出了当前main方法中的局部变量TestThreadOverview所持有的所有外部对象引用

incoming references查询结果为:

可以看到TestThreadOverview是main线程的一个本地局部变量,main线程本身还是一个GC root,而main线程在某个ThreadGroup中。 7、Paths to GC Roots

(从对象到GC Roots的路径) 和

Merge Shortest Paths to GC roots(从GC Roots到对象的共同路径)

从当前对象到GC roots的路径,这个路径解释了为什么当前对象还能存活,对分析内存泄露很有帮助,这个查询只能针对单个对象使用

Merge Shortest Paths to GC roots从GC roots到一个或一组对象的公共路径

Path to GC roots 和 Merge shortest Paths to GC roots 这两个查询都有很多选项,如:

意思是在查询到GC root的路径时,是包含所有引用,还是排除一些类型的引用(如软引用、弱引用、虚引用),从GC角度说,一个对象无法被GC,一定是因为有强引用存在,其它引用类型在GC需要的情况下都是可以被GC掉的,所以可以使用 exclude all phantom/weak/soft etc. references 只查看GC路径上的强引用Path to GC roots 和 Merge shortest Paths to GC roots 的入口和 List objects一样,可以从工具栏的 Query Browser 进入,或者在条目上直接点击右键进入

需要注意的是,Paths to GC roots是针对单个对象的,故在Histogram视图无法使用,因为Histogram视图是针对类的,只能使用Merge shortest Paths to GC roots查询

 8、Leak Suspects Report(内存泄露报告)

使用MAT打开一个Dump文件时,会弹出向导窗口,保持默认选项,点Finish,就会导向 Leak Suspects内存泄露报告页面

如果打开Dump时跳过了的话,也可以从其它入口进入,如

(1)工具栏上的 Run Expect System Test > Leak Suspects

(2)Overview页面的Reports部分

Leak Suspects 是MAT帮我们分析的可能有内存泄露嫌疑的地方,可以体现出哪些对象被保持在内存中,以及为什么它们没有被垃圾回收MAT提供了一个很贴心的功能,将报告的内容压缩打包到一个zip文件,并放在原始堆转储文件的目录下,一般命名为“xxx_Leak_Suspects.zip”,xxx是dump文件的名字,如果需要和同事一起分析这个内存问题的话,只需要把这个小小的zip包发给他就可以了,不需要把整个堆文件发给他。并且整个报告是一个HTML格式的文件,用浏览器就可以轻松打开。

内存泄露的概念:1、内存泄露的这些对象是从GC root可达的,从GC root存在通路可以与其相连
2、这些对象是无用的,即程序以后不会再使用这些对象
至于怎么定义程序不会再使用的对象,那就要看具体的程序逻辑了,说白了内存泄露就是该回收的内存没有被回收

下面用一个例子分析如何使用Leak Suspects Report内存泄露报告

public class OOMHeapTest {    public static void main(String[] args){        oom();    }    private static void oom(){        Map map = new HashMap();        Object[] array = new Object[1000000];        for(int i=0; i<1000000; i++){            String d = new Date().toString();            OOMBean o = new OOMBean(d, i);            map.put(i+"_oom", o);            array[i] = o;        }    }}

上面的代码中创建了很多OOMBean,并放入了Map和数组中,由于是强引用,在主线程运行结束前,GC自然不会回收,一直到内存溢出。在运行前设置一些VM参数:-Xms2m  -Xmx2m  -XX:+HeapDumpOnOutOfMemoryError以便程序可以OutOfMemory,并在发生内存溢出时自动生成内存快照程序运行一会儿后,控制台打印

java_pid10160.hprof 就是内存dump,可以在OOMHeapTest类所在工程的根目录下找到

Leak Suspects:

MAT工具分析了heap dump后在界面上非常直观的展示了一个饼图,该图深色区域被怀疑有内存泄漏,可以发现整个heap才6.8M内存,深色区域就占了92.11%。接下来是一个简短的描述,告诉我们main线程占用了大量内存,并且明确指出system class loader加载的“java.lang.Thread”实例有内存聚集,并建议用关键字“java.lang.Thread”进行检查。在下面还有一个“Details”链接,可以查看明细信息。

Details明细:

Details的最开始是Description描述,和前一个页面对内存泄露嫌疑点的描述一致,下面有一些与怀疑的内存泄露点关联的查询结果展示,是分析报告中认为可能会存在问题,协助我们深入分析问题根源的,具体如下:

(1)Shortest Paths To the Accumulation Point

实际上展开的视图是当前对象“java.lang.Thread @ 0xffc59ab0 main”的 Path to GC roots,即到GC roots的路径,点击标题右侧的按钮可以在另一窗口打开这个视图的作用是可以分析是由于和哪个GC root相连导致当前Retained Heap占用相当大的对象无法被回收由于是分析内存泄露的报告,找到导致当前对象无法被回收的GC roots,分析这些GC roots是否合理,是有必要的但本例中由于main线程本身就是GC root,故只有一条数据

(2)Accumulated Objects in Dominator Tree

这个视图以对象的维度展示了以当前对象“java.lang.Thread @ 0xffc59ab0 main”为根的 Dominator Tree支配树,可以方便的看出受当前对象“支配”的对象中哪个占用Retained Heap比较大观察Accumulated Objects部分,java.lang.Object[1000000]实例 和 java.util.HashMap 和 的Retained Heap(Size)最大,Retained Heap代表从该类实例沿着reference chain往下所能收集到的其他类实例的Shallow Heap(Size)总和,所以明显类实例都聚集在HashMap和Object数组中了在Accumulated Objects视图中,Retained heap占用最多的是HashMap和object数组,为啥它们会占用这么大的heap呢?这个时候需要分析HashMap和object数组中存放了一些什么对象?接着往下看 Accumulated Objects by Class in Dominator Tree

(3)Accumulated Objects by Class in Dominator Tree

这个视图实际上是展示了以当前对象“java.lang.Thread @ 0xffc59ab0 main”为根的 Dominator Tree支配树,并以Class类分组可以看到 OOMBean类 的实例最多,有11786个,程序中确实是在循环创建OOMBean实例,并放入object数据和HashMap中这样就可以确定Heap占用大是由于OOMBean类的实例创建的太多的原因了

(4)Thread Detail

Detail明细的最后由于当前怀疑泄露点为main Thread线程对象,故展示了线程明细信息,调用栈信息,对分析内存溢出的发生位置很有帮忙 。

内存分析诊断系列-理解heap dump记一次服务器被当肉鸡挖矿的经历如何编写一个可复用的SpringBoot应用运维脚本高效率编写Dockerfile需要绕过的一些坑Mysql百万量级数据高效导入Redis多线程之CountDownLatch的用法及原理笔记

我就知道你“在看”

mat分析dump分析_使用Eclipse Memory Analyzer Tool(MAT)分析线上故障(一)相关推荐

  1. jvm性能分析工具之-- Eclipse Memory Analyzer tool(MAT)

    性能分析工具之-- Eclipse Memory Analyzer tool(MAT)(一) 前言 性能分析工具之-- Eclipse Memory Analyzer tool(MAT)(一)中介绍了 ...

  2. jvm性能分析工具之-- Eclipse Memory Analyzer tool(MAT)(二)

    前言 在本文中,将介绍MAT如何根据heapdump分析泄漏根源.由于测试范例可能过于简单,很容易找出问题,但我期待借此举一反三. 一开始不得不说说ClassLoader,本质上,它的工作就是把磁盘上 ...

  3. 使用Memory Analyzer tool(MAT)分析内存泄漏(一)

    使用Memory Analyzer tool(MAT)分析内存泄漏(一) (2010年05月21日) 发表于 Java博客 前言的前言 :本文是自 2005 年 8 月以来,首次在一个月之内发布三篇文 ...

  4. 使用Memory Analyzer tool(MAT)分析内存泄漏

    http://www.blogjava.net/rosen/archive/2010/05/21/321575.html http://www.blogjava.net/rosen/archive/2 ...

  5. 使用Memory Analyzer tool(MAT)分析内存泄漏(二)

    前言 在 使用Memory Analyzer tool(MAT)分析内存泄漏(一)中,我介绍了内存泄漏的前因后果.在本文中,将介绍MAT如何根据heap dump分析泄漏根源.由于测试范例可能过于简单 ...

  6. 一次使用Eclipse Memory Analyzer分析weblogic内存溢出

    前言 在平时开发.测试过程中.甚至是生产环境中,有时会遇到OutOfMemoryError,Java堆溢出了,这表明程序有严重的问题.我们需要找造成OutOfMemoryError原因.一般有两种情况 ...

  7. eclipse无法创建java虚拟机_手把手:Java内存泄漏分析Memory Analyzer Tool

    点击上方"IT牧场",选择"设为星标"点击上方"IT牧场",选择"设为星标"技术干货每日送达 阅读文本大概需要3分钟. ...

  8. 一次使用 Eclipse Memory Analyzer 分析 Tomcat 内存溢出

    最近,线上生产系统突然频繁的 JVM 内存报警!但本系统近期内并没有上线改动! 为了能查清内存报警的原因,使用 Eclipse Memory Analyzer tool(MAT)对 JVM Dump ...

  9. eclipse占用内存过大_Java内存泄漏分析工具Memory Analyzer Tool

    一个大型的Java项目也许从开发到测试结束并可能不能未发现一些重大的问题,但是在生产环境中还是会出现一些非常棘手的问题,如内存泄漏直接导致服务宕机,遇到这样的问题对于一个经验尚浅的开发人员来说难度非常 ...

最新文章

  1. C#数据导出Excel详细介绍
  2. 高性能网络编程1----accept建立连接
  3. javaweb学习总结(二十八)——JSTL标签库之核心标签
  4. 【题意分析】1044 Shopping in Mars (25 分)【滑动窗口】
  5. Android之android studio如何获取证书指纹 (SHA1)
  6. autotools入门笔记(一)
  7. NE555延时电路设计
  8. 京瓷1125打印机清零_怎么设置京瓷1125MFP打印机ip地址
  9. 程序员的996简史!我们是怎么一步步陷入996工作制的
  10. Python学习_053.双分支选择结构_三元运算符的使用详解
  11. linux 查看任务管理器,LINUX查看进程的4种方法(小结)
  12. 用qq账号和密码实现登录网易云音乐
  13. OTL电路与OCL功放电路的区别
  14. 上大学之前,一定要明白这10大潜规则,你会少走很多人生弯路
  15. Graphics的平移与旋转
  16. js中数组的高逼格操作(filter、sort、map、reduce)
  17. screenfull全屏显示
  18. 《进击的虫师》当图虫遇到爬虫
  19. VISSIM4.30安装
  20. 一个VC爱好者的入门之路

热门文章

  1. java中的基本算法
  2. 2017年4月5号课堂笔记
  3. World of Warcraft .M2模型重建
  4. 夜晚较为活跃之物种对照图
  5. DSP及海思嵌入式板实现gb28181
  6. IDA保存修改的寄存器值
  7. SpringBoot之集成MybatisPlus
  8. wpf之auto与*的区别
  9. 查看Oracle的procedures,Oracle通过shell脚本查看procedure的信息
  10. quarts集群 运维_Quartz.Net分布式运用