【开发篇】四、MAT堆内存分析(Memory Analyzer Tool)

文章目录

  • 1、使用
  • 2、报错
  • 3、MAT支配树
  • 4、MAT内存泄漏的检测原理
  • 5、导出运行中系统的内存快照
  • 6、补充

1、使用

内存溢出后,分析泄露的思路是:

  • 在OOM前,将整个堆内存保存成一个hprof文件
  • MAT打开hprof文件,MAT自行分析可疑对象

添加JVM参数:

-XX:+HeapDumpOnOutOfMemoryError  //发生OutOfMemoryError错误时,自动生成hprof内存快照文件
-XX:HeapDumpPath=D:\myTmp\heap.hprof  //指定hprof文件的输出路径

模拟个OOM:
在这里插入图片描述

2、报错

在MAT里打开hprof文件:

【开发篇】四、MAT堆内存分析(Memory Analyzer Tool)_第1张图片

报错:

【开发篇】四、MAT堆内存分析(Memory Analyzer Tool)_第2张图片

很清晰了,下载JDK17或者换一个低版本的MAT(适配你配置的JDK版本的MAT),我当前是JDK11,下载地址【点击】

【开发篇】四、MAT堆内存分析(Memory Analyzer Tool)_第3张图片

这里同时配置两个版本的JDK,JDK11我还要用以后:

【开发篇】四、MAT堆内存分析(Memory Analyzer Tool)_第4张图片

classpath不变:

【开发篇】四、MAT堆内存分析(Memory Analyzer Tool)_第5张图片

JDK版本切到17后,改下mat目录下的MemoryAnalyzer.ini文件,文件内容后面追加以下内容(注意替换目录为自己JDK17的目录,且到bin一层):

-vm
D:\jdk\jdk-17\bin   

打开MAT:

【开发篇】四、MAT堆内存分析(Memory Analyzer Tool)_第6张图片

分析内存泄漏:

【开发篇】四、MAT堆内存分析(Memory Analyzer Tool)_第7张图片

大致概览,点击可查看这块是啥:

【开发篇】四、MAT堆内存分析(Memory Analyzer Tool)_第8张图片

点击Detail,查看怀疑对象线程的栈信息:

【开发篇】四、MAT堆内存分析(Memory Analyzer Tool)_第9张图片

重点看自己代码的栈信息,然后排查这一行写的是否有问题:

【开发篇】四、MAT堆内存分析(Memory Analyzer Tool)_第10张图片

3、MAT支配树

在对象引用图中,所有指向对象B的路径都经过对象A,则认为对象A支配对象B。

【开发篇】四、MAT堆内存分析(Memory Analyzer Tool)_第11张图片

再看对象D,引用图中想指向对象D,从近处看,可以是对象B,也可以对象C,所以对象B、C对D没有支配关系,往远看,对象A则可以支配对象D。同理,E被C支配,而C被A支配。演化出支配树后:

  • 支配树上对象本身所占空间称浅堆
  • 被对象A支配的所有对象,合起来叫深堆,也叫保留集

A的深堆,就是B、C、D、F、E这些对象加起来的大小,深堆浅堆的概念,表示了一个对象如果可以被回收,能释放多大的内存空间。

//练习

引用链到支配树:
【开发篇】四、MAT堆内存分析(Memory Analyzer Tool)_第12张图片

4、MAT内存泄漏的检测原理

用MAT验证下上面支配树的正确性,改JVM参数,这次不再等内存溢出时才生成内存快照,而是在Full GC后生成:

//添加JVM参数
-XX:+HeapDumpBeforeFullGC

运行上面练习的代码,并打开生成的快照文件。(卡了一小时没生成,不知道是不是JDK版本太高了,跳过了,反正这个参数也就这里用一下,生产环境狗都不用,卡的我莫名来气,贴个其他示意图)点击选择支配树,找到main线程节点:

【开发篇】四、MAT堆内存分析(Memory Analyzer Tool)_第13张图片

这里可以看到每个浅堆的深堆大小。

MAT就是根据支配树,从叶子节点向根节点遍历,如果发现深堆的大小超过整个堆内存的一定比例阈值,就会将其标记成内存泄漏的嫌疑对象、

5、导出运行中系统的内存快照

生产环境观察到堆内存在一直涨,想分析,肯定不能为了导一个快照模拟个OOM,这里导出运行中的快照:

方式一:过JDK自带的jmap命令导出

jmap -dump:live,format=b,file=文件路径和文件名 进程ID

参数含义:

//format=b,即以二进制的形式保存
//-dump:live,只导出标记为存活的对象
//进程ID,自己ps -ef找

方式二:阿尔萨斯的的heapdump

heapdump --live 文件路径和文件名

上面这个指令可以在tunnel服务端页面执行:

【开发篇】四、MAT堆内存分析(Memory Analyzer Tool)_第14张图片

也可以直接启动阿尔萨斯jar包后选择PID,再去执行。MAT打开快照,点击查看对象直方图,里面也显示了一个对象的浅堆和深堆大小,点击表头可排序,这种浅堆和深堆在一个数量级的,一般没问题。

【开发篇】四、MAT堆内存分析(Memory Analyzer Tool)_第15张图片
在这里插入图片描述

6、补充

MAT在打开当前的堆内存快照时,需要把快照下的堆内存里的所有对象读入到内存中,这对安装MAT的机器配置有要求,一般的开发桌面打不开这么大的快照文件,而且下载一个几十G的hprof文件,下行带宽小也头疼。这时可直接下载系统所在服务器对应操作系统对应的MAT:https://eclipse.dev/mat/downloads.php

./ParseHeapDump.sh 快照文件路径 org.eclipse.mat.api:suspects org.eclipse.mat.api:overview org.eclipse.mat.api:top_components
//三个参数的含义:
//org.eclipse.mat.api:suspects 生成内存泄漏检测报告
//org.eclipse.mat.api:overview 生成总览图
//org.eclipse.mat.api:top_components 生成组件图

执行脚本,启动MAT,分析堆内存,后生成报告,只需下载包告后解压,查看生成的这几个html报告查看即可。

【开发篇】四、MAT堆内存分析(Memory Analyzer Tool)_第16张图片

最后,MAT默认只使用了1G的堆内存,分析超过1G的快照文件,可调大MAT目录下的MemoryAnalyzer.ini这个值:

【开发篇】四、MAT堆内存分析(Memory Analyzer Tool)_第17张图片

你可能感兴趣的:(JVM,mat,heap,java)