如果 JVM 出现频繁 FullGC 该如何解决
JVM 频繁 FullGC(Full Garbage Collection)会导致频繁 STW(Stop The World),严重影响应用性能(如响应时间变长、吞吐量下降),核心解决思路是 “找到 FullGC 触发原因,针对性优化”,具体步骤如下:
# 1. 第一步:定位频繁 FullGC 的原因
通过以下工具和日志获取关键信息:
- 查看 GC 日志:开启 GC 日志(
-Xlog:gc*:file=gc.log:time,level,tags),分析 FullGC 的触发频率、回收时间、堆内存变化; - 使用监控工具:JVisualVM、Arthas、Prometheus+Grafana,查看老年代内存使用率、对象晋升情况、大对象分配;
- 常见原因:
- 老年代内存不足(大对象直接进入老年代、对象晋升过快);
- 内存泄漏(对象长期持有强引用,无法回收);
- 元空间不足(JDK 8+,类加载过多导致元空间满);
- 显式调用
System.gc()(强制 FullGC)。
# 2. 第二步:针对性解决方案
- 原因 1:老年代内存不足
- 优化 JVM 参数:增大老年代内存(如
-Xms4g -Xmx4g -XX:NewRatio=3,老年代占 3/4 堆内存); - 调整对象晋升策略:增大
-XX:MaxTenuringThreshold(对象晋升老年代的年龄,默认 15),让对象在新生代多停留一段时间,被 YGC 回收; - 避免大对象分配:将大对象(如超过 1MB 的数组、字符串)拆分,或用缓存替代频繁创建大对象。
- 优化 JVM 参数:增大老年代内存(如
- 原因 2:内存泄漏
- 排查泄漏对象:通过
jmap -dump:format=b,file=heapdump.hprof <pid>生成堆转储文件,用 MAT 工具分析,找到频繁创建且无法回收的对象(如静态集合未清理、线程池未关闭); - 修复泄漏点:清理静态集合、关闭无用线程 / 连接、移除未使用的监听器。
- 排查泄漏对象:通过
- 原因 3:元空间不足
- 调整元空间参数:增大
-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m,避免元空间频繁扩容触发 FullGC; - 减少类加载:避免动态生成过多类(如频繁使用反射、动态代理),清理无用的类加载器。
- 调整元空间参数:增大
- 原因 4:显式调用 System.gc ()
- 禁止显式 GC:添加 JVM 参数
-XX:+DisableExplicitGC,忽略System.gc()调用; - 排查代码:搜索项目中
System.gc()的调用,替换为合理的内存管理方式(如弱引用缓存)。
- 禁止显式 GC:添加 JVM 参数
# 3. 第三步:长期优化与监控
- 优化应用代码:减少大对象创建、避免内存泄漏、合理使用缓存(如 WeakHashMap);
- 调整 GC 收集器:若使用 CMS 收集器,频繁 FullGC 可能是内存碎片导致,可切换为 G1 收集器(支持分区回收,减少内存碎片);
- 建立监控告警:监控 FullGC 频率(如每分钟超过 1 次则告警)、STW 时间(如单次超过 1 秒则告警),及时发现问题;
- 定期复盘:分析 GC 日志和堆内存变化,持续优化 JVM 参数和应用代码。
上次更新: 12/30/2025