• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

无信不立

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

【JVM调优】MAT工具使用

一、功能整体示意

https://blog.csdn.net/x275920/article/details/123991656

https://www.cnblogs.com/lvxueyang/p/14833614.html (深堆,浅堆,OQL语言)

https://blog.csdn.net/lyd135364/article/details/121449969 (MAT工具使用)

https://blog.csdn.net/Dongguabai/article/details/123425128 (老年代内存工具查看)

http://www.manongjc.com/detail/28-mzjipprdmlptlzw.html(老年代内存工具查看)

https://www.cnblogs.com/ylz8401/p/15937892.html(老年代内存工具查看)

https://blog.csdn.net/a15835774652/article/details/125479631(mac上安装mat)

https://www.cnblogs.com/whaleX/p/14059972.html(修改MAT的内存配置)

https://zhuanlan.zhihu.com/p/535069800(MAT介绍)

http://wjhsh.net/wcss-p-12067606.html(OQL语言)

shallow heap 的大小单位是字节

Retained heap 的大小单位是字节

堆转储快照信息

jmap -dump:format=b,file=/home/heap.hprof 217533


查看老年代的对象信息(对象地址可以从GC日志中获取) SELECT
* FROM INSTANCEOF java.lang.Object t WHERE (toHex(t.@objectAddress) >= "0x720000000" AND toHex(t.@objectAddress) <= "0x7c0000000") 0x0000000720000000 0x00000007c0000000 0x00000007c0000000

 

 

 

1.1、获取dump文件的方式

获取堆快照 dump 文件(堆转储需要先执行 Full GC,线上服务使用时请注意影响),一般用三种方式:

  • 使用 JDK 提供的 jmap 工具,命令是 jmap -dump:format=b,file=<dumpfile> <pid>。当进程接近僵死时,可以添加 -F 参数强制转储:jmap -F -dump:format=b,file=<dumpfile> <pid>。

  • 本地运行的 Java 进程,直接在 MAT 使用 File → accquire heap dump 功能获取。

  • 启动 Java 进程时配置JVM参数:-XX:-HeapDumpOnOutOfMemoryError,当发生 OOM 时无需人工干预会自动生成 dump文件。指定目录用 -XX:HeapDumpPath=<filepath> 来设置。

1.2、一些小工具的说明

  • 对象级别分析的 Path to GC Root(到GC Root的路径)

  • with outgoing references(当前对象引用了那些对象信息)

  • with incoming references (那些对象引用了当前对象)

二、全局信息

堆内存大小、类数量、实例数量、Class Loader数量。

  • 全局概览信息,堆内存大小、类数量、实例数量、Class Loader数量。

  • Unreachable Object Histogram,展现转储快照时可被回收的对象信息(一般不需要关注,除非 GC 频繁影响实时性的场景分析才用到)

  • Biggest Objects by Retained Size,展现经过统计过的哪几个实例所关联的对象占内存总和较高,以及具体占用的内存大小,一般相关代码比较简单情况下,往往可以直接分析具体的引用关系异常,如内存泄漏等。此外也包含了最大对象和链接支持继续深入分析。

  • MAT 分析过的 Top Consumers (top消耗内存的信息)、Leak Suspects(内存泄漏嫌疑)等。

三、柱状图信息 Histogram

功能

  • 罗列每个类实例的数量、类实例累计内存占比,包括自身内存占用量(Shallow Heap)及支配对象的内存占用量(Retain Heap)。

  • 支持按对象数量、Retained Heap、Shallow Heap(默认排序)等指标排序;支持按正则过滤;支持按 package、class loader、super class、class 聚类统计,

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

 

 

使用场景

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

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

2). Histogram 支持使用正则表达式来过滤。例如,我们可以只展示那些匹配com.q.*的类

 

 3). 可以在 Histogram 的某个类继续使用 outgoing reference 查看对象分布,进而定位哪些对象是大头

 

 

 

 

四、支配树 Dominator Tree

功能

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

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

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

使用场景

  • 开始 Dump 分析时,首先应使用 Dominator tree 了解各支配树起点对象所支配内存的大小,进而了解哪几个起点对象是 GC 无法释放大内存的原因。

  • 当个别对象支配树的 Retained Heap 很大存在明显倾斜时,可以重点分析占比高的对象支配关系,展开子树进一步定位到问题根因,如下图中可看出最终是 SameContentWrapperContainer 对象持有的 ArrayList 过大

  • 在 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 所支配的内存均不大,这时需要聚合定位爆发点。

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

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

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

 

五、Leak Suspects

功能:具备自动检测内存泄漏功能,罗列可能存在内存泄漏的问题点。
使用入口:一般当存在明显的内存泄漏时,分析完Dump文件后就会展现,也可以如下图在 MAT 主页 → Leak Suspects。
使用场景:需要查看引用链条上占用内存较多的可疑对象。这个功能可解决一些基础问题,但复杂的问题往往帮助有限。
举例

  • 下图中 Leak Suspects 视图展现了两个线程支配了绝大部分内存。

  • 下图是点击上图中 Keywords 中 “Details” ,获取实例到 GC Root 的最短路径、dominator 路径的细信息。

 

 

六、Top Consumers

  • 功能:最大对象报告,可以展现哪些类、哪些 class loader、哪些 package 占用最高比例的内存,其功能 Histogram 及 Dominator tree 也都支持。

  • 使用场景:应用程序发生内存泄漏时,查看哪些泄漏的对象通常在 Dump 快照中会占很大的比重。因此,对简单的问题具有较高的价值。

 

七、配置MAT不忽略要垃圾回收对象

查询老年代对象列表的OQL语句

SELECT * FROM INSTANCEOF java.lang.Object t WHERE (toHex(t.@objectAddress) >= {老年代堆内存起始地址} AND toHex(t.@objectAddress) <= {老年代堆内存结束地址})

内存地址的确认方法

依赖应用服务的GC日志,查询老年代的起始地址和结束地址

开启 GC 日志

java -XX:+PrintGCDetails -XX:+HeapDumpBeforeFullGC -XX:+PrintHeapAtGC

得如如下类似日志

[PSYoungGen: 611840K->992K(612352K)] 1260846K->650606K(1308672K), 0.0047655 secs] [Times: user=0.03 sys=0.00, real=0.01 secs]

Heap after GC invocations=30667 (full 91):

PSYoungGen total 612352K, used 992K [0x00000000da800000, 0x0000000100000000, 0x0000000100000000)

eden space 610816K, 0% used [0x00000000da800000,0x00000000da800000,0x00000000ffc80000)

from space 1536K, 64% used [0x00000000ffc80000,0x00000000ffd78000,0x00000000ffe00000)

to space 1536K, 0% used [0x00000000ffe80000,0x00000000ffe80000,0x0000000100000000)

ParOldGen total 696320K, used 649614K [0x00000000b0000000, 0x00000000da800000, 0x00000000da800000)

object space 696320K, 93% used [0x00000000b0000000,0x00000000d7a63bf8,0x00000000da800000)

Metaspace used 69066K, capacity 70738K, committed 71936K, reserved 1114112K

class space used 7654K, capacity 8001K, committed 8192K, reserved 1048576K

}

可以看到 ParOldGen 对象的内存地址为 0x00000000b0000000,0x00000000d7a63bf8,0x00000000da800000

0x00000000b0000000 表示是 OldGen 的起始地址

0x00000000d7a63bf8 表示是使用到的地址. b0000000 ~ d7a63bf8

0x00000000da800000 表示 OldGen 的结束地址
View Code

 

posted on 2022-11-09 21:15  无信不立  阅读(1032)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3