1 引言
生产应用服务频繁Full GC却无法释放内存,甚至可能OOM,这种情况很有可能是内存泄露或者堆内存分配不足,此时需要dump堆信息来定位问题,查看是哪些地方内存泄漏。
Dump文件也称为内存转储文件或内存快照文件,是一个进程或者系统在某一个给定时间的内存快照。例如当进程崩溃或进程出现其它问题时,甚至在任何时候,我们都可以使用工具备份系统或进程的内存进行调试和分析。它包含模块信息、线程信息、堆栈调用信息、异常信息等。
2 查看java服务进程pid
ps -aux|grep java
3 GC简单分析
可使用jdk自带的jstat简单分析一下gc情况
# 每隔 1000毫秒输出一次 jstat -gcutil <pid> 1000
输出如下:
----------------------------------------
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 66.15 28.84 77.76 93.88 91.90 183 1.058 4 0.517 1.575
0.00 66.15 29.51 77.76 93.88 91.90 183 1.058 4 0.517 1.575
0.00 66.15 30.45 77.76 93.88 91.90 183 1.058 4 0.517 1.575
-----------------------------------------
S0:幸存区survivor0使用百分比
S1:幸存区survivor1使用百分比
E:新生代Eden使用百分比
O:老年代Old使用百分比
M:元数据 Metaspace使用百分比
CCS:压缩类空间Compressed class space使用百分比
YGC:Young GC次数
YGCT:Young GC耗时,毫秒
FGC:Full GC次数
FGCT:Full GC耗时,毫秒
GCT:GC总耗时
2次相邻的GC,可以快速判断那一次GC的耗时;GCT / GC = 平均每次GC耗时
GC是否频繁标准参考:Young GC执行迅速(50毫秒以内)、Young GC执行不频繁(间隔10秒左右一次)、Full GC执行迅速(1秒以内)、Full GC执行不频繁(间隔10分钟左右一次)
如发现Full GC次数频繁增加,Young GC次数不变或变化很小,这就是堆内存不足,很有可能就是内存泄漏的问题。
4 导出dump文件
分析dump文件首先要获取dump文件,获取方法基本有2种
4.1 设置JVM的环境变量
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/logs/xxx.hprof
那在OOM的时候会自动在指定目录生产dump文件,此时只需要在指定目录获取即可
4.2 通过jmap获取
jmap -dump:live,format=b,file=/logs/xxx.hprof <pid>
5 分析dump文件
对于小于自身电脑内存的dump文件,可尝试下载到本地进行分析,可使用的工具有:JVisualVM、JHat、MAT
5.1 使用JVisualVM
在jdk的bin目录下面有JVisualVM,打开它,然后选中文件->装入,选则dump文件,即可
点击异常错误的线程:XNIO-1 task-1,等待一会既可以打开堆转储上的线程的指定OOM的地方
查看具体实例数量和占用大小
点击类 -> 在实例数最多的类名上右击 -> 选择在实例视图中展示 -> 查看引用
右键选择在线程中显示,可以查询详情
5.2 使用jhat
jhat -J-Xmx1024M [file]
执行后等待console中输出Started HTTP on port 7000,看到后就可以通过浏览器访问http://ip:7000了,此页面默认为按package分类显示系统中所有的对象实例。在页面的最下端有Other Queries导航,其中有显示jvm中对象实例个数的链接、有显示jvm中对象大小的链接等,点击显示jvm中对象大小的链接,jhat在分析大的堆dump文件时表现不好,速度很慢。
5.3 使用mat(推荐)
5.3.1 下载
mat下载地址:https://eclipse.dev/mat/previousReleases.php
根据jdk版本下载合适的mat版本,可以通过uname -a命令查看服务器的操作系统版本号
[root@xxx ~]# uname -a
Linux xxxx 3.10.0-1127.19.1.el7.x86_64 #1 SMP Tue Aug 25 17:23:54 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
使用的是JDK1.8,系统是x86_64,需要选择如下版本:
5.3.2 解压
unzip MemoryAnalyzer-1.8.0.20180604-linux.gtk.x86_64.zip
5.3.3 修改内存
vi MemoryAnalyzer.ini
5.3.4 文件分析
./ParseHeapDump.sh [hprof文件] org.eclipse.mat.api:suspects org.eclipse.mat.api:overview org.eclipse.mat.api:top_components
其中hprof文件在实际使用的时候需要替换为hprof文件的路径。运行完毕后在hprof文件所在目录会生成一系列的index/threads文件和3个压缩文件。这3个压缩文件是我们重点关注的分析报告,分别为:
- xxx_Leak_Suspects.zip:报告包含怀疑造成内存泄漏的地方,报告中包含了class层级图。对于OOM的场景能够很容易的定位到是哪个对象占用了大量内存不释放。
- xxx_System_Overview.zip:包含heap dump基本信息,dump进程JVM的相关配置和线程信息等。
- xxx_Top_Components.zip:查看占用空间最大的几个object/class/classloader/package等。报告以饼图和表格的形式展示。通过这个报告可以定位出Java程序运行时哪些对象占用内存较多,对问题排查和程序优化很有帮助。
这三个报告是分析问题的关键。我们通过报告找出内存占用过大的对象,然后结合日志和项目源代码分析程序逻辑,逐步定位出问题。
主要看xxx_Leak_Suspects.zip,解压,打开index.html
大部分情况很容易看出问题出现在哪里,当前有时候可能需要进一步分析。
参考资料:
gc 查询java java 查看gc情况_mob6454cc61981e的技术博客_51CTO博客
https://www.cnblogs.com/east7/p/16989436.html
使用Linux的MAT分析工具分析超大dump文件(几GB)_准备起飞55的博客-CSDN博客
Java Heap Dump 分析步骤 - 简书
dump文件过大使用linux mat分析记录_dump文件太大怎么分析-CSDN博客