调用 System.gc() 不能保证立即触发 GC,也不推荐用于生产环境;应通过开启 GC 日志(JDK 8 用 -XX:+PrintGCDetails 等,JDK 9+ 用 -Xlog:gc)并分析日志中是否出现 “Full GC (System)” 等标识来验证效果,同时结合堆内存变化、STW 时间及内存泄漏排查综合评估。

调用 System.gc() 并不能保证立即触发 GC,也不推荐用于生产环境;要验证它是否起作用,关键不是“看它有没有被调用”,而是观察 JVM 实际是否发生了垃圾回收,并结合 GC 日志分析行为和效果。
开启 GC 日志输出
必须先让 JVM 记录 GC 行为,否则无法判断 System.gc() 是否引发回收。JDK 8 及以后推荐使用统一的 JVM 参数:
-
JDK 8:
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:gc.log -
JDK 9+(含 17/21):
-Xlog:gc*:gc.log:time,tags,level(更灵活,支持过滤) - 补充建议:
-XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=10M避免日志过大
在代码中合理触发并定位日志
System.gc() 是一个建议,JVM 可能忽略(尤其使用 G1 或 ZGC 时,默认禁用显式 GC)。若想提高被响应概率,可配合以下操作:
- 手动释放强引用(如置为
null)、清空集合、关闭资源后再调用 - 添加日志标记便于日志定位:
System.out.println("Before System.gc()"); System.gc(); System.out.println("After System.gc()"); - 注意:频繁调用会干扰 JVM 自适应策略,可能导致 STW 时间增加或 GC 频率异常
从 GC 日志中识别显式 GC
真正有效的 System.gc() 在日志中通常体现为带 “Full GC (System)” 或 “Allocation Failure” 后紧接 “System.gc()” 触发的回收(取决于 GC 算法和参数):
立即学习“Java免费学习笔记(深入)”;
- G1 中常见:
Full GC (System) ... [Eden: ..., Survivor: ..., Heap: ...] - Serial / Parallel GC 中可能显示:
Full GC (System.gc()) [PSYoungGen: ...] [ParOldGen: ...] - ZGC / Shenandoah 默认忽略
System.gc(),除非启用-XX:+ExplicitGCInvokesConcurrent,此时日志中会出现并发 GC 记录(非 Stop-The-World)
对比分析执行效果的关键指标
单次 System.gc() 效果需结合前后堆内存变化和耗时评估:
-
回收前后的堆占用:关注
Heap行中before→after的下降量(例如Heap: 1200M->320M) -
停顿时间(STW):Full GC 的
[Times: user=..., sys=..., real=...s]中real值即实际暂停时长 - 是否真正释放对象:如果日志显示 GC 后老年代/元空间仍高位,说明存在内存泄漏或对象被意外持有(如静态 Map、ThreadLocal、未关闭的连接)
- 建议搭配
jstat -gc <pid>实时观察,或用 VisualVM / JConsole 查看“Memory”页签中各代使用趋势


















