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




相关推荐
Theodore_102218 分钟前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee
冰帝海岸1 小时前
01-spring security认证笔记
java·笔记·spring
世间万物皆对象2 小时前
Spring Boot核心概念:日志管理
java·spring boot·单元测试
没书读了2 小时前
ssm框架-spring-spring声明式事务
java·数据库·spring
----云烟----2 小时前
QT中QString类的各种使用
开发语言·qt
lsx2024062 小时前
SQL SELECT 语句:基础与进阶应用
开发语言
小二·2 小时前
java基础面试题笔记(基础篇)
java·笔记·python
开心工作室_kaic3 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
向宇it3 小时前
【unity小技巧】unity 什么是反射?反射的作用?反射的使用场景?反射的缺点?常用的反射操作?反射常见示例
开发语言·游戏·unity·c#·游戏引擎
懒洋洋大魔王3 小时前
RocketMQ的使⽤
java·rocketmq·java-rocketmq