一、方法定义
public static void gc()
- 所属类:
java.lang.System
- 静态方法:直接通过
System.gc()
调用 - 返回值:
void
- 作用:向 JVM 发出建议执行垃圾回收的请求
⚠️ 关键点:它只是一个“建议”,JVM 可以选择忽略该请求。
二、功能说明
System.gc()
的主要功能是提示 JVM 运行垃圾回收器(Garbage Collector, GC),尝试回收不再使用的对象所占用的内存。
核心机制:
- 调用
System.gc()
等价于调用Runtime.getRuntime().gc()
- JVM 会根据当前内存状态、GC 策略、运行负载等因素自行决定是否立即执行 GC
- 不保证立即执行,也不保证执行完整的 Full GC
三、示例代码
1. 基本调用
public class GCDemo {
public static void main(String[] args) {
// 创建大量对象
for (int i = 0; i < 100000; i++) {
new Object();
}
System.out.println("调用 GC 前");
// 建议 JVM 执行垃圾回收
System.gc();
System.out.println("调用 GC 后");
}
}
2. 配合 finalize()
观察(已废弃,仅用于演示)
class FinalizeObject {
@Override
protected void finalize() throws Throwable {
System.out.println("对象被回收了!");
}
}
public class FinalizeDemo {
public static void main(String[] args) {
new FinalizeObject();
new FinalizeObject();
System.gc(); // 可能触发 finalize
}
}
🔴 注意:
finalize()
方法已在 Java 9 中标记为 @Deprecated,不推荐使用。
四、使用技巧
✅ 适用场景(极少):
性能测试/基准测试:
// 在测试前清理环境 System.gc(); Thread.sleep(100); // 等待 GC 完成 long start = System.currentTimeMillis();
内存敏感应用的“最后努力”:
try { // 分配大对象失败 byte[] data = new byte[1024 * 1024 * 100]; } catch (OutOfMemoryError e) { System.gc(); // 最后尝试释放内存 System.runFinalization(); // 强制执行 finalize(不推荐) // 再次尝试... }
JNI 或本地内存管理(配合其他机制)
五、常见错误与误解
错误 | 说明 |
---|---|
认为一定会触发 GC | ❌ JVM 可能完全忽略该调用 |
认为会立即执行 | ❌ GC 是异步的,可能延迟执行 |
依赖 GC 释放资源 | ❌ 应使用 try-with-resources 或显式 close() |
频繁调用以“优化性能” | ❌ 反而可能降低性能,引发频繁 GC |
替代手动资源管理 | ❌ GC 只回收内存,不保证释放文件、网络连接等 |
六、注意事项
- 不可靠性:
System.gc()
的效果依赖于 JVM 实现和 GC 算法(如 G1、ZGC、Shenandoah)。 - 性能影响:
- 可能触发 Stop-The-World 暂停
- 频繁调用会导致应用停顿、延迟增加
- JVM 参数控制:
-XX:+DisableExplicitGC
:可禁用System.gc()
(生产环境推荐)-XX:+ExplicitGCInvokesConcurrent
:让System.gc()
触发并发 GC,减少停顿
- JConsole/VisualVM 可见:手动 GC 调用会在监控工具中显示为 "System.gc()"
七、最佳实践
✅ 推荐做法:
- 避免显式调用:让 JVM 自动管理内存
- 生产环境禁用:
java -XX:+DisableExplicitGC MyApp
- 使用现代 GC 算法:如 ZGC、Shenandoah,支持低延迟、自动调优
- 监控代替干预:使用
jstat
,JFR
,Prometheus + Grafana
监控 GC 行为 - 优化对象生命周期:减少临时对象创建,复用对象池(谨慎使用)
❌ 避免做法:
- 在循环中调用
System.gc()
- 作为“内存泄漏修复”手段
- 在 Web 请求处理中调用
- 依赖其执行时机进行关键逻辑
八、性能优化建议
调优 JVM 参数,而非依赖
System.gc()
:-Xms2g -Xmx2g -XX:+UseZGC -XX:MaxGCPauseMillis=100
使用对象池(如
ByteBuffer
、数据库连接):// 使用 Netty 的 ByteBuf 池 // 而非频繁创建 byte[]
分析 GC 日志:
-Xlog:gc*:gc.log
使用工具分析:
GCViewer
,GCEasy.io
使用
Cleaner
替代finalize()
(Java 9+):Cleaner cleaner = Cleaner.create(); cleaner.register(obj, () -> System.out.println("清理资源"));
九、替代方案
需求 | 推荐替代方案 |
---|---|
内存清理 | JVM 自动 GC + 合理堆大小 |
资源释放 | try-with-resources , AutoCloseable |
对象销毁通知 | Cleaner (Java 9+) |
性能调优 | JVM 参数调优 + 监控 + 代码优化 |
强制内存释放 | -XX:+DisableExplicitGC + 健壮的内存管理 |
十、总结
项目 | 说明 |
---|---|
方法作用 | 向 JVM 建议执行垃圾回收 |
是否强制 | ❌ 否,JVM 可忽略 |
是否推荐 | ❌ 不推荐在生产代码中使用 |
主要用途 | 调试、测试、特殊场景 |
最佳实践 | 让 JVM 自动管理 GC,避免手动干预 |
趋势 | 现代 JVM(ZGC/Shenandoah)趋向于完全自动、低延迟 GC |
💡 一句话总结:
System.gc()
是一个“你可以尝试,但不应依赖”的方法。真正的性能优化在于合理的 JVM 配置、良好的代码设计和资源管理,而非手动触发 GC。
✅ 记住:不要在代码中写 System.gc()
,除非你非常清楚自己在做什么,且有充分的理由。