JVM 垃圾收集器

60 阅读5分钟

1. 概述

在本章内容中,我们将演示不同JVM 垃圾收集 (GC) 实现的基础知识。然后,我们将学习如何在应用程序中启用特定类型的垃圾收集。

2.垃圾回收简介

顾名思义,垃圾回收似乎会查找并删除内存中的垃圾。但实际上,垃圾回收会跟踪 JVM 堆空间中可用的每个对象,并删除未使用的对象。

基本上,GC分为两个简单的步骤,称为标记和清除:

  • 标记—— 这是垃圾收集器识别哪些内存正在使用、哪些内存未使用的地方。
  • 清除—— 此步骤删除在“标记”阶段识别的对象。

优点:

  • 无需手动分配/释放内存,因为未使用的内存空间由GC自动处理**
  • 无需处理*悬垂指针*
  • 自动*内存泄漏*管理(GC本身不能保证完全解决内存泄漏问题;但是,它可以解决很大一部分问题)

缺点:

  • 由于JVM必须跟踪对象引用的创建/删除,因此此活动需要比原始应用程序更多的 CPU 能力。它可能会影响需要大量内存的请求的性能。
  • 程序员无法控制用于释放不再需要的对象的 CPU 时间的调度。
  • 使用某些 GC 实现可能会导致应用程序不可预测地停止。
  • 自动内存管理不会像适当的手动内存分配/释放那样高效。

3. GC 实现

JVM有四种类型的GC实现:

  • 串行垃圾收集器
  • 并行垃圾收集器
  • G1 垃圾收集器
  • Z 垃圾收集器

3.1. 串行垃圾收集器

这是最简单的 GC 实现,因为它基本上与单个线程一起工作。因此,GC实现在运行时会冻结所有应用程序线程。因此,在多线程应用程序(如服务器环境)中使用它不是一个好主意。

不过, Twitter工程师在 2012 年 QCon 上就串行垃圾收集器的性能做了一个精彩的演讲,这是一个更好地理解该收集器的好方法。****

对于大多数对暂停时间要求不高且在客户端计算机上运行的应用程序,串行 GC 是首选的垃圾收集器。要启用串行垃圾收集器,我们可以使用以下参数:

java -XX:+UseSerialGC -jar Application.java复制

3.2. 并行垃圾收集器

它是 Java 5 到 Java 8 中JVM的默认GC,有时也称为吞吐量收集器。与串行垃圾收集器不同,它使用多个线程来管理堆空间,但在执行 GC时也会冻结其他应用程序线程。**********

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

可以使用命令行选项*-XX:ParallelGCThreads=* 控制垃圾收集器线程的数量。

使用命令行选项*-XX:MaxGCPauseMillis=* 指定最大暂停时间目标(向垃圾收集器提示希望暂停时间 毫秒或更短) 。**

执行垃圾收集所花费的时间与垃圾收集之外所花费的时间之比称为最大吞吐量目标,可以通过命令行选项*-XX:GCTimeRatio= 指定。*

使用选项 -Xmx 指定最大堆占用空间(程序运行时所需的堆内存量)

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

java -XX:+UseParallelGC -jar Application.java

3.3. G1垃圾收集器

G1(垃圾优先)垃圾收集器专为在具有大内存空间的多处理器机器上运行的应用程序而设计。它从JDK7 Update 4及更高版本开始提供。

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

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

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

java -XX:+UseG1GC -jar Application.java复制

3.4. Java 8 的变化

Java 8u20引入了一个JVM参数,用于减少因创建过多相同字符串实例而导致的不必要的内存使用。该参数通过将重复的 字符串值移至全局单个char[] 数组来优化堆内存。

我们可以通过添加***-XX:+UseStringDeduplication**作为JVM*参数来启用此参数。

3.5. Z 垃圾收集器

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

ZGC会并发执行所有昂贵的工作,而不会停止应用程序线程的执行超过 10 毫秒,这使其非常适合需要低延迟的应用程序。它使用带有彩色指针的负载屏障在线程运行时执行并发操作,并使用它们来跟踪堆使用情况。

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

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

要启用Z 垃圾收集器,我们可以在低于 15 的JDK版本中使用以下参数:

java -XX:+UnlockExperimentalVMOptions -XX:+UseZGC Application.java复制

从版本 15 开始,我们不需要开启实验模式:

java -XX:+UseZGC Application.java复制

我们应该注意ZGC不是默认的垃圾收集器。

4 结论

在本文中,我们研究了不同的JVM 垃圾收集实现及其用例。