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




相关推荐
尘浮生34 分钟前
Java项目实战II基于Spring Boot的智慧生活商城系统的设计与实现(开发文档+数据库+源码)
java·开发语言·数据库·spring boot·mysql·maven·生活
工作不忙1 小时前
关于SwitchCase中变量定义及使用变量的一些注意事项参数传递参数时不能实现多态动态绑定的问题c++语法
开发语言·c++·windows·开源·开源软件
安祝老师2 小时前
十四届蓝桥杯STEMA考试Python真题试卷第二套第二题
开发语言·python·算法·青少年编程·蓝桥杯
疯一样的码农3 小时前
Java初学者指南
java·开发语言
Shaun8883 小时前
Basic bash script tutorial
开发语言·bash
立黄昏粥可温3 小时前
Python 从入门到实战44(Pandas读写数据)
开发语言·python·pandas
muke_r3 小时前
C++——文件操作
开发语言·c++
cdut_suye3 小时前
Python编程探索:从基础语法到循环结构实践
开发语言·python·学习
LUwantAC3 小时前
Java学习路线:JUL日志系统(一)日志框架介绍
java·开发语言·学习
梦里水乡8573 小时前
基于MATLAB的农业病虫害识别研究
开发语言·matlab