在Java生态系统不断增强的动态格局中,人们可能会忽略近年来Java 垃圾收集(GC)方面取得的重要进展。同时,最新一代的 GC 为运行 Java 应用程序带来了深远的影响。本文旨在强调 ZGC 和 Shenandoah 给我们带来的重大影响。
垃圾收集
垃圾回收是 Java 区别于其他许多编程语言的一个特性。GC 机制通过自动查找和删除应用程序不再使用的对象,免除了开发过程中手动内存管理的麻烦。
然而,我们应该更深入地了解 CG 的运行原理,选择适合应用程序目标的 CG,以优化代码的性能,避免常见的内存相关错误;尤其是当 Java 运行时有多种垃圾收集器可用,以不同的开销成本为代价来优化各种指标。
GC 与应用程序并行工作,因此,它会与应用程序争夺内部资源。Java 应用程序中的 GC 承担着许多角色:
- 为新对象分配内存
- 监视应用程序可以通过堆中的引用链访问哪些对象
- 释放那些没有
通过执行这些功能,GC 会自动清理内存。
如果使用老一代的 GC,我们已经习惯了某种程度的潜在扩展玻璃天花板,那么现代 GC 正在改变 Java 实践,提供以前无法实现的垂直扩展。
JVM内存结构
堆是 Java 程序内存的一部分,用于存储对象。不再需要的对象称为垃圾。JVM 管理此内存,释放不再需要的空间,并以最佳方式放置活动对象。此过程称为垃圾收集。
Java 堆分为几代,每代都有不同的用途,以优化内存管理和垃圾收集。
以下是 Java 中 CG 生成的简短列表:
- 新创建对象的年轻代
- 老生代用于存放那些在经历几轮 GC 后从年轻代区域到达此处的长期对象
- Metaspace (成熟 LTS 版本中用于替代 PermGen),存储类和方法的元数据:与 PermGen 不同,Metaspace 可以动态扩展,虽然可以动态扩展,但可以通过 JVM 设置控制其最大大小,从而管理元数据的内存消耗。
不同代的组装各不相同,并不一定同时发生。对于垃圾收集器 (GC) 来说,其存在的根源是弱代假说(大多数对象都早逝)。
不同类型的 GC 需要针对应用程序的目标指标进行不同的设置。正确的指标设置可确保 Java 应用程序的高效率。内存管理取决于这些设置,根据个人需求启用这些设置可实现优化的内存管理。不过,GC 有一些限制,并且必须在工作中暂停,这在大型复杂应用程序中可能会导致操作延迟。
GC 有助于简化 Java 开发。各种类型的 GC 都需要针对特定应用程序的目标指标进行量身定制的设置。正确的设置可确保 Java 应用程序的高效率。内存管理取决于这些设置,根据个人需求启用它们可实现优化的内存管理。
ZGC 和 Shenandoah 如何改变 Java 运行
随着应用程序用户数量的不断增长以及 Java 工作负载的庞大而复杂,旧的 GC 有时无法应对现代数据量,导致应用程序工作出现明显暂停或内存使用量和OutOfMemeryError消息增加(当 JVM 或其他平台在尝试运行应用程序时内存不足时)。
随着 Java 编码变得越来越复杂,人们设计了两种新的 GC 来克服旧 GC 工具的缺点:ZGC 和 Shenandoah。
Z 垃圾收集器
Z垃圾收集器(ZGC)是作为Java11中的实验性收集器引入的,随着JEP-377的实现,它成为 JDK 15 中可用于生产的功能。
ZGC 旨在管理现代应用程序中常见的大量内存。当今的 Java 应用程序承载着大量内存,管理这些内存需要 GC 具备增强的技术技能。
ZGC 是一种可扩展的低延迟垃圾收集器,可以并发执行所有昂贵的工作,而不会使应用程序线程的执行停止超过 10 毫秒。它适用于需要超低延迟或使用大型堆(多 TB)的应用程序。
ZGC优于旧版 GC,它为每个阶段激活了一个复杂的过程:
- 参考着色来存储参考状态
- 应用负载屏障来检查引用的元数据位
- 根据彩色引用和负载障碍,它执行重新映射,创建不同的引用。
- 与应用程序并行重新分配内存
Shenandoah
Shenandoah GC是一种垃圾收集器,旨在最大限度地减少暂停时间。由于在运行 Java 线程的同时运行内存清理过程,因此暂停时间会增加。Shenandoah 具有允许独立于 GC 暂停时间的功能。因此,200 MB 和 200 GB 堆的暂停时间同样短。Shenandoah 通过为每个 Java 对象添加一个额外的间接指针来实现这种稳定性,这允许 GC 线程在 Java 线程继续执行的同时压缩堆。
Shenandoah GC 从 JDK 15 开始包含在产品功能中。其主要特性包括:
- 并发性:它与应用程序并行运行并同时压缩,从而避免碎片问题。
- 操作分为 3 个或 2 个并发阶段,其中遍历阶段(或遍历模式)已弃用
- 目标是暂停时间小于 10 毫秒
-
基于位置的 GC,使 Shenandoah 能够独立收集每个区域而无需记忆集。
Shenandoah GC适用于需要进行短暂垃圾收集暂停的应用程序,无论堆大小如何。
有效的 Java 运行和更大的垂直扩展
为了更好地理解 ZGC 和 Shenandoah 给 Java 生态系统带来的影响,让我们回顾一下它们旨在解决的问题的根源。
旧 GC 的低延迟与 GC 工作中的长时间暂停和大堆大小有关。这两个指标随着应用程序复杂性的增加而增长。此外,Java 扩展的隐形障碍部分是由于硬件限制。就在最近,20 GB 的内存被认为是很大的,而今天我们以 TB 为单位进行操作。该技术在软件和硬件方面都得到了发展,为新的扩展范围提供了广泛的内存大小。
随着硬件功能的扩展,我们已经进入了软件开发的新现实。为了有效地利用当今的内存量,我们可以利用现有的 Java 代码和库,并通过升级和迁移 Java 应用程序来扩展它们。为了安排这种扩展,公司需要开发团队和资源。
现代 GC 提供了实现相同结果的另一种途径。使用 ZGC 和 Shenandoah 可以实现相同的扩展,而无需重写代码、额外资源和开发团队参与。现在,企业可以继续使用相同的应用程序,只需添加相关的 GC 即可更有效地运行 Java。
通过代码重写扩展 Java 工作负载是一个复杂的过程,需要特殊的专业知识。但是,由于 GC 设置位于 JVM 内部,因此企业可以轻松访问这些质量工具,从而以方便、廉价的方式进行垂直扩展。
ZGC 和 Shenandoah 是出色的工具,展示了当今 Java 的发展方向。现代 Java 开发使用简单方便的工具来提高应用程序效率,而无需额外的预算或深厚的专业知识。
现有的 ZCG 和 Shenandoah 的进一步改进体现在分代 GC上。分代 GC 采用改进的算法,可以减少内存使用量并减少暂停次数。它们专注于清理年轻一代中的短寿命内存。分代方法进一步优化了垃圾收集过程。要选择最合适的 GC,您可能需要咨询 OpenJDK 供应商;这是当今实现高质量 Java 垂直扩展的最快途径。