Java 的 7 种垃圾回收机制

了解 Java 中可用于内存管理的各种选择。
6 位读者喜欢这篇文章。

使用 C 和 C++ 等编程语言编写的应用程序需要您在内存中不再需要对象时对其进行销毁编程。应用程序增长越大,您忽略释放未使用的对象的可能性就越大。这会导致内存泄漏,最终耗尽系统内存,并且在某个时候没有更多的内存可分配。这导致应用程序因 OutOfMemoryError 而失败。但是在 Java 中,垃圾回收 (GC) 在应用程序执行期间自动发生,因此减轻了手动释放和可能的内存泄漏的任务。

垃圾回收不是一个简单的任务。Java 虚拟机 (JVM) 有八种不同的垃圾回收机制,了解每一种机制的用途和优势很有用。

1. 串行 GC

使用单个线程的 GC 的原始实现。当垃圾回收发生时,它会暂停应用程序(通常称为“停止世界”事件)。这适用于可以承受小暂停的应用程序。垃圾回收占用空间小,因此这是嵌入式应用程序的首选 GC 类型。可以在运行时启用此垃圾回收样式

$ java -XX:+UseSerialGC

2. 并行 GC

与串行 GC 一样,它也使用“停止世界”方法。这意味着在 GC 进行时,应用程序线程会暂停。但在这种情况下,有多个线程执行 GC 操作。这种类型的 GC 适用于在多线程和多处理器环境中运行的中型到大型数据集的应用程序。

这是 JVM 中的默认 GC,也称为吞吐量收集器。可以使用适当的 JVM 标志调整各种 GC 参数,如吞吐量、暂停时间、线程数和占用空间

  • 线程数:-XX:ParallelGCThreads=<N>
  • 暂停时间:-XX:MaxGCPauseMillis=<N>
  • 吞吐量(与实际应用程序执行相比,用于 GC 的时间):-XX:GCTimeRatio=<N>
  • 最大堆占用空间:-Xmx<N>
  • 可以显式启用并行 GC:java -XX:+UseParallelGC。使用此选项,年轻代的次要 GC 由多个线程完成,但旧代的 GC 和压缩由单个线程完成。

还有一个称为并行旧 GC的并行 GC 版本,它对年轻代和老年代都使用多个线程

$ java -XX:+UseParallelOldGC

3. 并发标记清除 (CMS)

并发标记清除 (CMS) 垃圾回收与应用程序并行运行。它对次要 GC 和主要 GC 都使用多个线程。在删除未使用的对象后,不会在 CMS GC 中执行实时对象的压缩,因此暂停的时间比其他方法要短。此 GC 与应用程序并发运行,这会降低应用程序的响应时间。这适用于暂停时间短的应用程序。此 GC 在 Java 8u 中已弃用,并从 14u 开始完全删除。但是,如果您仍在使用的 Java 版本包含它,则可以使用以下方式启用它

$ java -XX:+UseConcMarkSweepGC

在 CMS GC 的情况下,应用程序会暂停两次。第一次暂停是在标记直接可访问的活动对象时。此暂停称为初始标记。在 CMS GC 阶段结束时,它会第二次暂停,以解释并发周期中遗漏的对象,即当应用程序线程在 CMS GC 完成后更新对象时。这被称为重新标记阶段

4. G1 (Garbage First) GC

Garbage first (G1) 旨在取代 CMS。G1 GC 是并行、并发和增量压缩的,具有低暂停时间。G1 使用与 CMS 不同的内存布局,将堆内存划分为大小相等的区域。G1 使用多个线程触发全局标记阶段。标记阶段完成后,G1 知道哪个区域可能大部分是空的,并首先选择该区域进行扫描/删除阶段。

在 G1 的情况下,大小超过区域一半的对象被认为是“巨型对象”。这些对象被放置在老年代中,在一个适当的名为巨型区域的区域中。要启用 G1

$ java -XX:+UseG1GC

5. Epsilon GC

此 GC 在 11u 中引入,是一个no-op(不执行任何操作)GC。Epsilon 仅管理内存分配。它不进行任何实际的内存回收。只有在您知道应用程序的确切内存占用量,并且知道它是无垃圾回收的情况下,才使用 Epsilon。

$ java -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC

6. Shenandoah

Shenandoah 在 JDK 12 中引入,是一种 CPU 密集型 GC。它执行压缩、删除未使用的对象,并立即将可用空间释放到操作系统。所有这些都与应用程序线程本身并行发生。要启用 Shenandoah

$ java -XX:+UnlockExperimentalVMOptions \ 
-XX:+UseShenandoahGC

7. ZGC

ZGC 专为具有低延迟要求并使用大型堆的应用程序而设计。ZGC 允许 Java 应用程序在执行所有垃圾回收操作时继续运行。ZGC 在 JDK 11u 中引入,并在 JDK 12 中得到改进。从 JDK 15 开始,Shenandoah 和 ZGC 都已从实验阶段移出。要启用 ZGC

$ java -XX:+UnlockExperimentalVMOptions -XX:+UseZGC

灵活的垃圾回收

Java 为内存管理提供了灵活性。熟悉可用的不同方法很有用,以便您可以选择最适合您正在开发或运行的应用程序的方法。

标签
User profile image.
Jayashree Huttanagoudar 是 Red Hat India Pvt ltd 的高级软件工程师。她与 Middleware OpenJDK 团队合作。她总是渴望学习新事物,这有助于她的工作。

1 条评论

调用垃圾回收器的不同方式有哪些?

Creative Commons License本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。
© . All rights reserved.