Memory Analyzer (MAT)

TIPS 本文基于MAT 1.10.0编写。该版本最低支持JDK 8

Memory Analyzer又名Memory Analyzer Tool,简称MAT,可以作为独立软件,也可作为Eclipse插件存在。它是一个快速且功能丰富的Java堆内存分析器,可帮助您查找内存泄漏并减少内存消耗。相关地址:

MAT的主要功能:

  • 找出内存泄漏的原因
  • 找出重复引用的类和jar
  • 分析集合的使用
  • 分析类加载器

    概念

    Shallow vs. Retained Heap(浅堆与保留堆)

  • 浅堆(Shallow Heap):一个对象消耗的内存。一个对象引用需要32或64 bit(取决于OS体系结构),每个Integer 4个字节,每个Long 8个字节等。根据堆转储格式,这个大小也可能会被调整(例如,对齐为8bit),从而更好地模拟VM的实际消耗量。

  • X的保留集(Retained set):当X被垃圾回收时,由GC删除的对象集。同理,如果X没有被回收,那么该集合中的对象都会“保留下来”。
  • X的保留堆(Retained heap):X的保留集中的所有对象的浅层大小的总和,即X保持活动的内存。换而言之,Retained heap指的是对象X的保留内存大小,即由于它的存活导致多大的内存没有被回收。
  • 前导对象集的保留集(例如特定类的所有对象,或特定类加载器加载的所有类的所有对象,或者仅仅是一堆任意对象):前导对象不可达时,被释放的那些对象。

一般来说,对象的浅堆是对象在堆中的大小,而同一对象的保留大小是在垃圾回收对象时将释放的堆内存量。
Retained set包括这些对象以及只能通过这些对象访问的所有其他对象。保留大小是保留集中包含的所有对象的总堆大小。
第三方工具-Memory Analyzer (MAT) - 图1
TIPS
如图,A和B是GC Roots(例如:方法参数、局部变量,或者调用了wait()、notify()或synchronized()的对象)可以看出:

  • E的存在,会导致G无法被回收,因此E的Retained set是E和G;
  • C的存在,会导致E、D、F、G、H都无法被回收,因此C的Retined set是C、E、D、F、G、H;
  • A和B的存在,会导致C、E、D、F、G、H都无法被回收,因此A和B的Retained set是A、B、C、E、D、F、G、H。

最小保留大小给出了良好的保留估计,其计算速度快于一组对象的确切保留大小。它仅取决于检查集中的对象数,而不取决于堆转储中的对象数。

Dominator Tree(支配树)

MAT提供了对象图的支配树。通过将对象参考图转换为支配树,您可以轻松地识别最大的保留内存块以及对象之间的依赖关系。下面是术语的非正式定义

  • X支配Y:如果对象图中从起始(或Root)节点到Y的每条路径都必须经过X,那么就说对象X支配对象Y
  • 直接支配者:某个对象路径最短的支配者

支配树是在对象图的基础上建立的,在支配树中,每个节点都是其子节点的直接支配者。因此,基于支配树可以轻松看出对象之间的依赖关系。
支配者树具有以下重要属性:

  • 对象从属于X的子树(例如对象被X支配)就是X的Retained set也就是说,X节点的子树是所有被X支配的节点集合,也就是X的Retained set;
  • 如果X是Y的直接支配节点,那么支配X的节点也可以支配Y
  • 支配树中的边并不直接对应于对象图中的对象引用

第三方工具-Memory Analyzer (MAT) - 图2

使用

  • 独立软件版本:前往 https://www.eclipse.org/mat/downloads.php ,根据自己的操作系统,下载安装即可使用。百度盘加速:

    1. 链接:https://pan.baidu.com/s/1HXjzNDpzin6fXGrZPyQeWQ 密码:aon2
  • Eclipse插件版本:在Eclipse插件中心安装即可使用。

    欢迎页面

    第三方工具-Memory Analyzer (MAT) - 图3
    TIPS
    来自朋友阿杜的文章 https://www.jianshu.com/p/9990fb95bb5a

    主要功能项

  • inspector:透视图,用于展示一个对象的详细信息,例如内存地址、加载器名称、包名、对象名称、对象所属的类的父类、对象所属的类的加载器对象、该对象的堆内存大小和保留大小,gc root信息。下半部分展示类的静态属性和值、对象的实例属性和值、对象所属的类的继承结构。

  • Heap Dump History:列出最近分析过的文件
  • 功能选择栏:从左到右依次是:概览、类直方图、支配树、OQL查询、线程视图、报告相关、详细功能。其中概览就是上图的这个页面,其他则提供了一些更细致的分析能力。总的来说,功能上和VisualVM大同小异,但分析得更加细致。
  • 饼图:展示retained size对象占用比例
  • Actions:常用的内存分析动作
    • Histogram:列出内存中的对象,对象的个数及其大小。点击后生成的报表:
      • Class Name : 类名称,java类名
      • Objects : 类的对象的数量,这个对象被创建了多少个
      • Shallow Heap :一个对象内存的消耗大小,不包含对其他对象的引用
      • Retained Heap :是shallow Heap的总和,也就是该对象被GC之后所能回收到内存的总和
    • Dominator Tree:列出最大的那些对象,以及他们为什么存活。
    • Top Consumers:打印最昂贵的对象,以内和包分组
    • Duplicate Classes:检测被多个classloader加载的类
  • Reports:报表
    • Leak Suspects:自动分析内存泄漏的原因,并能直接定位到Class,找到可能导致内存泄露的代码行数。
    • Top Components:列出占用超过1%的组件的报告信息
  • Step by Step:

    • Top Components:分析从属于指定包或者class loader的对象。

      个人遇到的问题

      启动报如下异常:
      1. java.lang.IllegalStateException: The platform metadata area could not be written: /private/var/folders/xt/xkf315314t38ct3144c_wz4c0000gp/T/AppTranslocation/1B159134-8301-46AC-B119-CB67BA8452F6/d/mat.app/Contents/MacOS/workspace/.metadata. By default the platform writes its content
      解决方案:
      把mat.app挪到macOS的应用目录下并重启即可。当然也可修改 mat.app/Contents/Eclipse/MemoryAnalyzer.ini 。
      参考文档:
  • https://www.eclipse.org/forums/index.php/t/1091808/

  • https://www.eclipse.org/forums/index.php/t/214452/
  • https://github.com/cncgoko/Goko/issues/56
  • https://www.vogella.com/tutorials/EclipseMemoryAnalyzer/article.html
  • https://community.bonitasoft.com/blog/acquire-heap-dump-mat-memory-analyzer-tool

    拓展阅读

    朋友的文章:

  • 利用MAT玩转JVM内存分析(一)

  • MAT入门到精通(二)