Java GC 垃圾回收

JVM Garbage Collection 简称 GC,被称之为 Java 垃圾回收机制。

垃圾回收简介

从名字上看,垃圾回收处理从内存中查找和删除垃圾。实际上,垃圾回收会跟踪 JVM 堆空间中的每个可用对象并删除未使用的对象。

简而言之,GC工作在两个简单的步骤中,称为标记和擦除 (Mark & Sweep):

  • 标记 Mark 垃圾收集器在此识别哪些内存正在使用,哪些未使用
  • 擦除 Sweep 此步骤删除在“标记”阶段识别的对象

JVM 自动的垃圾回收机制有如下的优点:

  • 无需手动分配/释放内存,因为未使用的内存空间由GC自动处理
  • 没有处理空指针的开销
  • 自动内存泄漏管理(GC本身不能保证完全证明内存泄漏的解决方案,但是,它会处理其中的很大一部分)

当然,它也存在一定的不足:

  • 由于JVM必须跟踪对象引用的创建/删除,此活动需要比原始应用程序更多的 CPU 资源,它可能会影响需要大内存的请求的性能
  • 程序员无法精准控制专用于释放不再需要的对象
  • 使用某些 GC 实现可能会导致应用程序意外停止
  • 自动内存管理不会像正确的手动内存分配/释放那样有效

垃圾回收实现

JVM 有五种类型的GC实现:

  • 串行垃圾收集器 Serial Garbage Collector
  • 并行垃圾收集器 Parallel Garbage Collector
  • CMS 垃圾收集器 CMS Garbage Collector
  • G1 垃圾收集器 G1 Garbage Collector
  • Z 垃圾收集器 Z Garbage Collector

串行垃圾收集器

这是最简单的 GC 实现,因为它基本上使用单个线程。结果,这个GC实现在运行时暂停了所有应用程序线程。因此,不建议在服务器环境等多线程应用程序中使用它。

Serial GC 是大多数应用程序的首选垃圾收集器,这些应用程序对暂停时间要求不高且在客户端式机器上运行。

要启用串行垃圾收集器,我们可以使用以下参数:

java -XX:+UseSerialGC -jar Application.java

并行垃圾收集器

Parallel GC 是JVM的默认GC收集器。与串行垃圾收集器不同,它使用多个线程来管理堆空间。但它也会在执行GC时暂停其他应用程序线程。

如果我们使用这个GC,我们可以指定最大垃圾收集线程和暂停时间、吞吐量和占用空间(堆大小)。

  • -XX:ParallelGCThreads= 控制垃圾收集器线程的数量
  • -XX:MaxGCPauseMillis= 指定最大暂停时间目标(两次GC之间的间隔[以毫秒为单位]) 。
  • -XX:GCTimeRatio= 进行垃圾收集所花费的时间与在垃圾收集之外花费的时间的比值称为最大吞吐量。
  • -Xmx 指定最大堆占用空间(程序运行时所需的堆内存量) 。

要启用Parallel Garbage Collector,我们可以使用以下参数:

java -XX:+UseParallelGC -jar Application.java

CMS 垃圾收集器

Concurrent Mark Sweep (CMS) 使用多个垃圾收集器线程进行垃圾收集。也就是说它可以不停止正常程序以执行垃圾收集。

需要注意的一点是,由于此GC是并发的,因此在并发进程工作时调用显式垃圾收集(例如使用System.gc())将导致并发模式失败/中断。

如果超过 98% 的总时间花在CMS垃圾收集上,而回收的堆不到 2%,则CMS收集器会抛出OutOfMemoryError。如有必要,可以通过在命令行中添加选项-XX:-UseGCOverheadLimit来禁用此功能。

此收集器还有一种称为增量模式的模式,该模式在 Java SE 8 中已被弃用,可能会在未来的主要版本中删除。

要启用CMS 垃圾收集器,我们可以使用以下标志:

java -XX:+UseParNewGC -jar Application.java

从 Java 9开始,CMS 垃圾收集器已被弃用。因此,如果我们尝试使用它,JVM 会打印一条警告消息:

>> java -XX:+UseConcMarkSweepGC --version
Java HotSpot(TM) 64-Bit Server VM warning: Option UseConcMarkSweepGC was deprecated 
in version 9.0 and will likely be removed in a future release.
java version "9.0.1"

Java 14 完全放弃了对 CMS 的支持:

>> java -XX:+UseConcMarkSweepGC --version
OpenJDK 64-Bit Server VM warning: Ignoring option UseConcMarkSweepGC; 
support was removed in 14.0
openjdk 14 2020-03-17

G1 垃圾收集器

G1(垃圾优先)垃圾收集器专为在具有大内存空间的多核 CPU 机器上运行的应用程序而设计。它从 JDK7 开始可用。

G1收集器将取代CMS收集器,因为它更高效。

与其他收集器不同,G1收集器将堆划分为一组大小相等的堆区域,每个区域都是连续的虚拟内存范围。在执行垃圾回收时,G1显示了一个并发的全局标记阶段(即阶段 1,称为标记),以确定整个堆中对象的活跃度。

标记阶段完成后,G1知道哪些区域大部分是空的。它首先在这些区域收集,这通常会产生大量的可用空间(即第 2 阶段,称为清扫)。这就是为什么这种垃圾收集方法被称为 Garbage-First 的原因。

要启用G1 垃圾收集器,我们可以使用以下参数:

java -XX:+UseG1GC -jar Application.java

Z 垃圾收集器

ZGC(Z Garbage Collector) 是一种可扩展的低延迟垃圾收集器,它在 Java 11 中作为 Linux 的实验性选项首次亮相。JDK 14 在 Windows 和 macOS 操作系统下引入了ZGC 。ZGC从 Java 15 开始获得生产状态。

ZGC并发执行所有昂贵的工作,不会停止应用程序线程的执行超过 10 毫秒,这使其适用于需要低延迟的应用程序。它使用带有染色指针 (Colored Pointers) 的负载屏障 (Load Barrier) 在线程运行时执行并发操作,并且它们用于跟踪堆使用情况。

染色指针是ZGC的核心概念。这意味着ZGC使用一些引用位(元数据位)来标记对象的状态。它还可以处理大小从 8MB 到 16TB 的堆。此外,暂停时间不会随着堆、活动集或根集的大小而增加。

与G1 类似,Z 垃圾收集器对堆进行分区,只是堆区域可以有不同的大小。

要启用Z Garbage Collector,从版本 15 开始,我们可以使用以下参数:

java -XX:+UseZGC Application.java

转载请注明出处:码谱记录 » Java GC 垃圾回收
标签: