JVM出现频繁Full GC

bash 复制代码
java.lang.reflect.InvocationTargetException
at sun.reflect.GeneratedMethodAccessor948.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.xxl.job.core.handler.impl.MethodJobHandler.execute(MethodJobHandler.java:31)
at com.xxl.job.core.thread.JobThread.run(JobThread.java:163)
Caused by: java.lang.OutOfMemoryError: GC overhead limit exceeded

Full GC,全称Full Garbage Collection,翻译成中文就是"完全垃圾回收"。它会清理堆内存中所有分代(新生代、老年代、永久代/元空间)里的无用对象。简单说,当JVM觉得"我这堆内存快被占满了",它就会触发Full GC来释放内存空间。

Full GC的触发条件一般有以下几种:

1、老年代空间不足:当新生代对象过多,晋升到老年代,而老年代空间不足时,JVM就会触发Full

GC。这个情况比较常见,尤其在做批量操作、处理大对象时更容易发生。

2、永久代/元空间满了:如果使用的是JDK 7或者之前的版本,永久代满了也会触发Full GC。而在JDK

8以后引入了元空间(Metaspace)来替代永久代,这种情况相对较少,但依然有可能。

3、System.gc():某些代码里可能存在手动调用System.gc(),这就会强制触发Full

GC。这种情况你可能在某些"聪明"的开发者写的代码中见过,但实际项目中基本没人会这么干,因为它的副作用太大。

4、内存分配策略问题:有时候JVM在做内存分配时,为了安全起见,会触发Full

GC。比如:老年代剩余的连续内存空间小于新生代对象的总大小时,JVM可能会选择触发Full GC。

5、代码中有大对象:大对象直接进入老年代。比如那种"地图类"的业务对象,如果在短时间内频繁创建,老年代很容易被撑爆。
快速解决: 重启项目
通过以下几步来排查

1、启用GC日志

在JVM启动参数里加上: -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:/path/to/gc.log

这段配置会把GC的详细信息打印到日志文件中。你可以在gc.log里查看Full GC发生的频率和原因。

查看内存分配情况

可以使用jmap命令: jmap -histo:live

是你的Java进程ID。这条命令会显示所有对象在内存中的分布情况,告诉你每种类型的对象占了多大空间

导出内存堆快照

jmap -dump:format=b,file=heapdump.hprof

把堆内存导出来,用工具(如Eclipse MAT)分析。通过分析内存快照,你可以找出哪些对象占用了最多的空间

监控老年代使用率

jstat -gcutil 1000

这会每隔1秒打印一次GC信息。你可以观察老年代(Old)的使用率是否过高。如果老年代经常在80%以上,可能就会频繁触发Full GC

调整JVM参数

可以通过调优JVM参数来减少Full GC发生的频率。常用参数有

-Xms4g -Xmx4g -Xmn2g -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m -XX:+UseG1GC 这里用G1收集器是因为它能更好地处理大内存场景,减少Full GC的发生频率。如果你用的是CMS或者Parallel GC,可以考虑切换到G1。

检查是否有大对象

代码中存在大对象,尽量避免在短时间内频繁创建

像这种大列表,一旦被创建,就直接晋升到老年代,容易导致Full GC。解决方案是拆分大对象,或者减少使用频率

增加堆内存

堆内存加大了,Full GC发生的频率自然就会下降。不过,现实中你可能会遇到客户嫌弃"加内存太贵"

避免手动调用 System.gc()

检查代码中是否存在手动调用System.gc()的地方,改掉就好了。如果项目中确实需要显式调用,可以考虑加上参数:

-XX:+DisableExplicitGC

这样就可以禁用显式的GC调用,防止因为误操作导致的Full GC。

使用更好的内存分配策略

比如使用-XX:MaxGCPauseMillis=200来控制每次GC的最大暂停时间。这个参数告诉JVM你希望每次GC的暂停时间不要超过200ms,从而减少Full GC的发生。

JDK1.8及以前自带内存监控工具

使用方法可参考链接: https://blog.csdn.net/u011250186/article/details/131698661




相关推荐
PieroPc几秒前
Python 写的 智慧记 进销存 辅助 程序 导入导出 excel 可打印
开发语言·python·excel
2401_857439693 小时前
SSM 架构下 Vue 电脑测评系统:为电脑性能评估赋能
开发语言·php
SoraLuna3 小时前
「Mac畅玩鸿蒙与硬件47」UI互动应用篇24 - 虚拟音乐控制台
开发语言·macos·ui·华为·harmonyos
xlsw_3 小时前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis
神仙别闹4 小时前
基于java的改良版超级玛丽小游戏
java
Dream_Snowar4 小时前
速通Python 第三节
开发语言·python
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭4 小时前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
暮湫5 小时前
泛型(2)
java
超爱吃士力架5 小时前
邀请逻辑
java·linux·后端
南宫生5 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论