一文深度讲解JVM 内存分析工具 MAT及实践(建议收藏)

本文深入解析MAT内存分析工具的使用,包括内存分布、对象依赖、对象状态和条件检索四大方面,通过实例展示Dominator Tree、Histogram、Leak Suspects等关键功能,帮助Java开发者有效诊断和解决堆内存问题。
摘要由CSDN通过智能技术生成

1. 前言

熟练掌握 MAT 是 Java 高手的必备能力,但实践时大家往往需面对众多功能,眼花缭乱不知如何下手,小编也没有找到一篇完善的教学素材,所以整理本文帮大家系统掌握 MAT 分析工具。

本文详细讲解 MAT 众多内存分析工具功能,这些功能组合使用异常强大,熟练使用几乎可以解决所有的堆内存离线分析的问题。我们将功能划分为4类:内存分布详情、对象间依赖、对象状态详情、按条件检索。每大类有多个功能点,本文会逐一讲解各功能的场景及用法。此外,添加了原创或引用案例加强理解和掌握。

如图所示:

一文深度讲解JVM 内存分析工具 MAT及实践(建议收藏)

为减少对眼花缭乱的菜单的迷茫,可以通过下图先整体熟悉下各功能使用入口,后续都会讲到。

一文深度讲解JVM 内存分析工具 MAT及实践(建议收藏)

2. 内存分布详解及实战

2.1 全局信息概览

功能:展现堆内存大小、对象数量、class 数量、class loader 数量、GC Root 数量、环境变量、线程概况等全局统计信息。

使用入口:MAT 主界面 → Heap Dump Overview。

举例:下面是对象数量、class loader 数量、GC Root 数量,可以看出 class loader 存在异常。

一文深度讲解JVM 内存分析工具 MAT及实践(建议收藏)

举例:下图是线程概况,可以查看每个线程名、线程的 Retained Heap、daemon 属性等。

一文深度讲解JVM 内存分析工具 MAT及实践(建议收藏)

使用场景 全局概览呈现全局统计信息,重点查看整体是否有异常数据,所以有效信息有限,下面几种场景有一定帮助:

  • 方法区溢出时(Java 8后不使用方法区,对应堆溢出),查看 class 数量异常多,可以考虑是否为动态代理类异常载入过多或类被反复重复加载。
  • 方法区溢出时,查看 class loader 数量过多,可以考虑是否为自定义 class loader 被异常循环使用。
  • GC Root 过多,可以查看 GC Root 分布,理论上这种情况极少会遇到,笔者只在 JNI 使用一个存在 BUG 的库时遇到过。
  • 线程数过多,一般是频繁创建线程但无法执行结束,从概览可以了解异常表象,具体原因可以参考本文线程分析部分内容,此处不展开。

2.2 Dominator tree

注:笔者使用频率的 Top1,是高效分析 Dump 必看的功能。

功能

  • 展现对象的支配关系图,并给出对象支配内存的大小(支配内存等同于 Retained Heap,即其被 GC 回收可释放的内存大小)
  • 支持排序、支持按 package、class loader、super class、class 聚类统计

使用入口:全局支配树: MAT 主界面 → Dominator tree。

举例: 下图中通过查看 Dominator tree,了解到内存主要是由 
ThreadAndListHolder-thread 及 main 两个线程支配(后面第2.6节会给出整体案例)。

一文深度讲解JVM 内存分析工具 MAT及实践(建议收藏)

使用场景

  • 开始 Dump 分析时,首先应使用 Dominator tree 了解各支配树起点对象所支配内存的大小,进而了解哪几个起点对象是 GC 无法释放大内存的原因。
  • 当个别对象支配树的 Retained Heap 很大存在明显倾斜时,可以重点分析占比高的对象支配关系,展开子树进一步定位到问题根因,如下图中可看出最终是 SameContentWrapperContainer 对象持有的 ArrayList 过大。

一文深度讲解JVM 内存分析工具 MAT及实践(建议收藏)

  • 在 Dominator tree 中展开树状图,可以查看支配关系路径(与 outgoing reference 的区别是:如果 X 支配 Y,则 X 释放后 Y必然可释放;如果仅仅是 X 引用 Y,可能仍有其他对象引用 Y,X 释放后 Y 仍不能释放,所以 Dominator tree 去除了 incoming reference 中大量的冗余信息)。
  • 有些情况下可能并没有支配起点对象的 Retained Heap 占用很大内存(比如 class X 有100个对象,每个对象的 Retained Heap 是10M,则 class X 所有对象实际支配的内存是 1G,但可能 Dominator tree 的前20个都是其他class 的对象),这时可以按 class、package、class loader 做聚合,进而定位目标。
  • 下图中各 GC Roots 所支配的内存均不大,这时需要聚合定位爆发点。

一文深度讲解JVM 内存分析工具 MAT及实践(建议收藏)

在 Dominator tree 展现后按 class 聚合,如下图:

一文深度讲解JVM 内存分析工具 MAT及实践(建议收藏)

可以定位到是 SomeEntry 对象支配内存较多,然后结合代码进一步分析具体原因。

一文深度讲解JVM 内存分析工具 MAT及实践(建议收藏)

在一些操作后定位到异常持有 Retained Heap 对象后(如从代码看对象应该被回收),可以获取对象的直接支配者,操作方式如下。

一文深度讲解JVM 内存分析工具 MAT及实践(建议收藏)

一文深度讲解JVM 内存分析工具 MAT及实践(建议收藏)

2.3 Histogram 直方图

注:笔者使用频率 Top2

功能

  • 罗列每个类实例的数量、类实例累计内存占比,包括自身内存占用量(Shallow Heap)及支配对象的内存占用量(Retain Heap)。
  • 支持按对象数量、Retained Heap、Shallow Heap(默认排序)等指标排序;支持按正则过滤;支持按 package、class loader、super class、class 聚类统计,

使用入口:MAT 主界面 → Histogram;注意 Histogram 默认不展现 Retained Heap,可以使用计算器图标计算,如下图所示。

一文深度讲解JVM 内存分析工具 MAT及实践(建议收藏)

使用场景

  • 有些情况 Dominator tree 无法展现出热点对象(上文提到 Dominator tree 支配内存排名前20的占比均不高,或者按 class 聚合也无明显热点对象,此时 Dominator tree 很难做关联分析判断哪类对象占比高),这时可以使用 Histogram 查看所有对象所属类的分布,快速定位占据 Retained Heap 大头的类。

使用技巧

  • Integer,String 和 Object[] 一般不直接导致内存问题。为更好的组织视图,可以通过 class loader 或 package 分组进一步聚焦,如下图。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值