一、方法定义

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,不推荐使用。


四、使用技巧

✅ 适用场景(极少):

  1. 性能测试/基准测试

    // 在测试前清理环境
    System.gc();
    Thread.sleep(100); // 等待 GC 完成
    long start = System.currentTimeMillis();
    
  2. 内存敏感应用的“最后努力”

    try {
        // 分配大对象失败
        byte[] data = new byte[1024 * 1024 * 100];
    } catch (OutOfMemoryError e) {
        System.gc(); // 最后尝试释放内存
        System.runFinalization(); // 强制执行 finalize(不推荐)
        // 再次尝试...
    }
    
  3. JNI 或本地内存管理(配合其他机制)


五、常见错误与误解

错误 说明
认为一定会触发 GC ❌ JVM 可能完全忽略该调用
认为会立即执行 ❌ GC 是异步的,可能延迟执行
依赖 GC 释放资源 ❌ 应使用 try-with-resources 或显式 close()
频繁调用以“优化性能” ❌ 反而可能降低性能,引发频繁 GC
替代手动资源管理 ❌ GC 只回收内存,不保证释放文件、网络连接等

六、注意事项

  1. 不可靠性System.gc() 的效果依赖于 JVM 实现和 GC 算法(如 G1、ZGC、Shenandoah)。
  2. 性能影响
    • 可能触发 Stop-The-World 暂停
    • 频繁调用会导致应用停顿、延迟增加
  3. JVM 参数控制
    • -XX:+DisableExplicitGC:可禁用 System.gc()(生产环境推荐)
    • -XX:+ExplicitGCInvokesConcurrent:让 System.gc() 触发并发 GC,减少停顿
  4. JConsole/VisualVM 可见:手动 GC 调用会在监控工具中显示为 "System.gc()"

七、最佳实践

✅ 推荐做法:

  • 避免显式调用:让 JVM 自动管理内存
  • 生产环境禁用
    java -XX:+DisableExplicitGC MyApp
    
  • 使用现代 GC 算法:如 ZGC、Shenandoah,支持低延迟、自动调优
  • 监控代替干预:使用 jstat, JFR, Prometheus + Grafana 监控 GC 行为
  • 优化对象生命周期:减少临时对象创建,复用对象池(谨慎使用)

❌ 避免做法:

  • 在循环中调用 System.gc()
  • 作为“内存泄漏修复”手段
  • 在 Web 请求处理中调用
  • 依赖其执行时机进行关键逻辑

八、性能优化建议

  1. 调优 JVM 参数,而非依赖 System.gc()

    -Xms2g -Xmx2g
    -XX:+UseZGC
    -XX:MaxGCPauseMillis=100
    
  2. 使用对象池(如 ByteBuffer、数据库连接):

    // 使用 Netty 的 ByteBuf 池
    // 而非频繁创建 byte[]
    
  3. 分析 GC 日志

    -Xlog:gc*:gc.log
    

    使用工具分析:GCViewer, GCEasy.io

  4. 使用 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(),除非你非常清楚自己在做什么,且有充分的理由。