堆内存占用很小 但是 JVM 频繁full gc 问题排查

最近碰到一个头疼的Full gc 问题,系统运行缓慢,但是使用 jstat -gcutil pid工具一看,堆内存占用不到10%,为啥会这样?

堆内存占用很小 但是 JVM 频繁full gc 问题排查

堆内存占用很小 但是 JVM 频繁full gc 问题排查

查看JVM配置如下 :

-Xms8G -Xmx8G -XX:NewRatio=4 XX:MaxPermSize=512m -Djava.awt.headless=true -XX:+UseCompressedOops -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps

嗯?gc方式没有指定?

使用Jconsole连上去看下VM概要,看下gc方式是啥,年老代的Full gc 时间与次数都不正常:

垃圾收集器:  名称 = 'PS MarkSweep', 收集 = 56, 总花费时间 = 6.000 分
垃圾收集器:  名称 = 'PS Scavenge', 收集 = 47, 总花费时间 = 49.776 秒
竟然并行收集不靠谱,尝试使用并发收集,-XX:+UseConcMarkSweepGC -XX:+UseParNewGC
-XX:CMSFullGCsBeforeCompaction=5 -XX:+UseCMSCompactAtFullCollection

结果Full gc的更厉害了,平均一秒一次。

是什么问题导致了一直gc? 经过网上大神的指导,使用命令 jstat -J-Djstat.showUnsupported=true -snap [pid]  查看平均晋升空间,结果也不是这个问题,平均晋升空间远小于old区剩余空间呢。

大神的频繁Full gc 解决问题链接:https://blog.csdn.net/xeseo/article/details/11925375

后来经网友提醒, jstat -gccause pid 查看gc详细原因(一开始怎么没想到查看full gc原因,还是太嫩了,停留于表层的问题排查。)

堆内存占用很小 但是 JVM 频繁full gc 问题排查


发现程序中显示调用了 System.gc(),原因是程序中使用到了DirectorByteBuffer,使用了直接内存引用,程序每进行一次梳理,都进行一次 System.gc()的调用,以免发生OOM,但是调用也太频繁了,堆内存空间完全足够呢,就调用了System.gc()。

殊不知调用System.gc时,系统会建议执行Full GC,但是不必然执行,所以频繁发生了Full gc 问题。

调整程序,当堆内存不足的时候,才调用System.gc(),问题解决。