你不能在 Java 中强制进行垃圾收集。你可以使用一些策略让 Java 虚拟机确定任务的优先级,但垃圾收集的不确定性意味着不能强制执行该过程。
同样,你也无法阻止 Java 垃圾回收的发生。你可以更改 Java 虚拟机 (JVM) 中的一些配置设置,这些设置会影响触发垃圾收集 (GC) 例程的变量,但你无法完全阻止 Java GC 的发生。或者你可以吗?
Epsilon GC,也称为 Java 的无操作垃圾收集器,提供内存分配工具,但它不执行任何内存回收。Epsilon GC 不只是阻止 Java 垃圾收集的发生——它完全消除了 GC。
Epsilon GC 是随 JDK 11 发布的一项实验性功能。要在启用了 Epsilon GC 的 JVM 上启动应用程序或微服务,请包括以下 JVM 选项:
-XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC
Epsilon GC 的优缺点
那么,Epsilon GC 有什么了不起的呢?使用它将应用程序和微服务部署到 JVM 的 DevOps 专业人员可以获得最低的内存管理延迟。
缺点?当 JVM 达到其分配内存的限制时,它会崩溃并出现 OutOfMemoryError,从而终止 JVM。一旦 Java 堆用完,就不能再分配对象了。而且由于不允许内存回收,JVM 将失败,并将 OutOfMemoryError 写入日志并将堆转储写入文件系统。
何时使用 Epsilon GC
为什么会有人想使用一个正常运行有可能终止 JVM 的 Java 内存管理工具? Epsilon GC 有一些有效的用例,包括:
性能测试例程,其中 GC 例程会扭曲收集的指标;
JVM 在退出时终止的极其短暂的例程;
适用于内存占用已确定的超延迟敏感应用程序;
对于主要执行迭代和条件逻辑的无垃圾应用程序;
用于 Kubernetes 上基于 Java 的高度集群化微服务部署,其中间歇性 JVM 故障不太可能导致服务降级;
对于在启动时分配大量内存然后在工作日结束时循环关闭的服务器。
Epsilon GC 的一个常见用例是确定 JVM 的最佳内存管理设置。要确定应用程序的最佳 Java 堆大小设置,可以在打开无操作垃圾收集器的负载下测试应用程序。然后可以使用 Java Flight Recorder 和 JDK Mission Control 等分析工具来确定最小和最大堆大小的最佳 Xms 和 Xmx 设置。这种方法生成的性能指标不受执行内存回收所需的额外开销的影响。
当开发人员和 DevOps 专业人员询问停止 JVM 的能力时,他们通常希望将其延迟 10 或 15 分钟,以避免在关键服务窗口期间发生停止世界事件。但是,没有这样的命令、API 或 JDK 实用程序会暂时暂停 Java GC。
最接近的可用选项是利用 Epsilon GC、JEP-318 并完全关闭 GC。然后,围绕不可避免的堆转储和 OutOfMemoryError 构建 Java 内存管理策略,如果对象创建超过分配给堆的内存量,就会发生这种情况。