OpenJDK 17 中的 Shenandoah:亚毫秒级 GC 停顿「译」

2023-10-27 19:59

本文主要是介绍OpenJDK 17 中的 Shenandoah:亚毫秒级 GC 停顿「译」,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

  一、前言

  Shenandoah OpenJDK 垃圾收集(GC) 项目的主要动机是减少垃圾收集暂停时间。在 JDK 12 中,发布了原始的 Shenandoah 垃圾收集器,它实现了并发堆疏散,解决了在不停止应用程序的情况下清理(可能很大)堆的主要问题。这个版本最终被移植到 JDK 11。在 JDK 14 中,实现了并发类卸载,在 JDK 16 中,添加了并发引用处理,这两者都进一步减少了垃圾收集操作的暂停时间。暂停下剩余的垃圾收集操作是线程堆栈处理,已经在 JDK 17 中 解决了这个问题。

  本文介绍了 Shenandoah GC 中新的并发线程堆栈处理。在 JDK 17 中并发处理线程堆栈为我们提供了可靠的亚毫秒级暂停。

  二、Java中的线程处理

  什么是线程处理,为什么我们需要为它停止应用程序?Java 程序在线程中执行,每个线程拥有一个栈:栈帧的列表,每个帧保存着局部变量、监视器以及与当前执行的方法相关的其他信息。最重要的是,在 Java 垃圾收集的上下文中,它保存对堆对象的引用(例如,引用类型化对象的局部变量)。

  当垃圾收集周期开始时,我们首先扫描所有线程的堆栈,以使用我们在堆栈上找到的引用来播种标记队列。我们在GC 暂停(安全点)时这样做,因为我们需要在标记开始时堆栈的一致状态,而不是线程的执行并发地与堆栈混淆。完成后,我们继续执行并遍历可达对象的图,从我们在初始线程扫描期间找到的引用开始。

  同样,当将可到达的对象疏散到空区域时,我们需要更新线程堆栈上的所有引用以指向新的对象位置。我们需要暂停一下,因为垃圾收集加载屏障通常在从堆加载引用时起作用(例如加载到局部变量或寄存器中),这意味着局部变量或寄存器在需要 GC 的状态下不能有对象引用干涉。到那时,通过垃圾收集屏障为时已晚。为每个局部变量或寄存器访问快速调用垃圾收集屏障会遇到性能问题。

  扫描和处理线程堆栈需要时间。小型工作负载(具有小堆栈的少量线程)可能只需要几毫秒来扫描,但是大型工作负载——应用程序服务器,我正在看着你!——很容易花费几十毫秒来处理。所有这些处理都是在应用程序停止时完成的,因此它会影响应用程序的整体端到端延迟。

  三、OpenJDK 17 中的并发线程处理

  我们如何改善这种情况并同时处理线程堆栈?我们通过使用一种称为堆栈水印的机制(最初由 ZGC 开发人员实现)来实现这一点。中心观察是所有线程堆栈的操作都发生在最顶层的框架中:当前执行的方法。下面的所有帧基本上都是静态的并且不会改变——它们可以被垃圾收集线程安全地并发扫描。我们需要做的就是在堆栈帧被销毁时(例如,通过返回调用者,或通过抛出异常)协调 GC 线程与正在执行的线程,从而退出 GC 处理。这种协调是通过堆栈水印实现的,一个告诉我们堆栈的哪些部分可以安全扫描的指针,以及一个允许垃圾收集器处理返回的屏障。图 1 说明了堆栈水印在并发线程处理中的作用。

  

  并发线程处理中的堆栈水印。

  四、在垃圾收集期间使用堆栈水印

  让我们考虑一个例子。比如说,在标记开始时,在初始暂停期间,我们将堆栈水印设置为每个线程的最顶层帧并武装线程。这意味着我们认为所有帧对于并发扫描都是安全的,但没有(还)可以执行。从安全点返回后,我们将控制权交还给 Java 程序,因此需要顶层框架才能安全执行。在这里,堆栈水印屏障开始发挥作用,让垃圾收集器处理顶部帧(出于实际原因,还有它的调用者)。线程将扫描顶部帧并相应地降低水印,并在安全点之前离开的点恢复自己的执行。同时,GC 线程也开始扫描堆栈,从底部向上到水印,即在安全区中。

  将水印降低一帧。防止 GC 线程扫描超出该水印。通过扫描任何引用来处理现在位于水印上方的帧。

  最终结果是我们将有效地扫描所有相同的帧和引用,就像我们在初始标记暂停时所做的那样,但我们是在程序执行时同时进行的。

  五、Shenandoah GC 基准测试

  那么这些变化在实践中会产生什么影响呢?我已经运行了许多衡量垃圾收集暂停的基准测试。下表显示了 JDK 11、JDK 16 和 JDK 17 中所有基准测试的平均暂停时间。JDK 16 和 JDK 17 之间的差异显示了并发堆栈处理所实现的改进。与 JDK 11 的区别是为了完整性而显示的,包括与以前版本相比的各种其他改进。

  

  六、发行版

  Shenandoah 的可用性因供应商和 JDK 版本而异。默认情况下,OpenJDK 12+ 构建通常包括 Shenandoah。OpenJDK 11 需要在构建时选择加入。

  已知供应商状态为:

  红帽Fedora 24+ OpenJDK 8+ 版本包括 ShenandoahRHEL 7.4+ 附带 OpenJDK 8+,其中包括作为技术预览的Shenandoah适用于 Windows 的 Red Hat OpenJDK 8u 版本 包括 Shenandoah亚马逊从 OpenJDK 11.0.9 开始,在 Amazon Corretto 中提供 ShenandoahOracle不在 任何版本中发布 Shenandoah,包括 OpenJDK 构建和专有构建。Azul从 OpenJDK 11.0.9 开始,在 Azul Zulu 中发布 Shenandoah。OpenJDK从 OpenJDK 11.0.9 开始,以默认二进制文件形式提供 ShenandoahLinux 发行版Debian 从 OpenJDK 11.0.9 开始发布 ShenandoahIcedTea 的 Gentoo ebuild 具有 Shenandoah USE 标志基于 RHEL/Fedora 的发行版或其他使用其软件包的发行版也可能启用了 Shenandoah。值得注意的是, 众所周知,CentOS、 Oracle Linux 和 Amazon Linux 都发布了它。七、启用 Shenandoah

  使用 -XX:+UseShenandoahGC JVM 选项通过 Shenandoah GC 运行您的 Java 应用程序。

  java -XX:+UseShenandoahGC

  7.1 模式

  模式定义了 Shenandoah 多运行的主要方式。并定义了主要的性能特征。可以使用 -XX:ShenandoahGCMode=选择模式 。可用模式有:

  normal/satb(默认)。此模式使用 Snapshot-At-The-Beginning (SATB) 标记运行并发 GC。这种标记模式类似于 G1 所做的:通过“前一个”对象拦截写入和标记。iu(实验性)。此模式使用增量更新 (IU) 标记运行并发 GC。这种标记模式是SATB 模式的镜像:通过“新”对象拦截写入和标记。这可能会使标记不那么保守,尤其是在访问弱引用方面。passive(诊断)。此模式运行 stop-the-world GC。此模式用于功能测试,但有时它对于用 GC 屏障平分性能异常或计算应用程序中的实际实时数据大小很有用。7.2 基本配置

  基本配置和命令行选项:

  -Xlog:gc (自 JDK 9 起)或 -verbose:gc (至 JDK 8)将打印各个 GC 计时。-Xlog:gc+ergo(自 JDK 9 起)或 -XX:+PrintGCDetails(至 JDK 8)或 将打印启发式决策,这可能会揭示异常值(如果有)。-Xlog:gc+stats (自 JDK 9 起)或 -verbose:gc (至 JDK 8)将在运行结束时打印关于雪兰多内部计时的汇总表。

  在启用日志记录的情况下运行几乎总是一个好主意。这个汇总表传达了有关 GC 性能的重要信息,我们几乎不可避免地会在性能错误报告中要求提供。启发式日志对于找出 GC 异常值很有用。

  其他推荐的 JVM 选项是:

  -XX:+AlwaysPreTouch:将堆页面提交到内存有助于减少延迟中断-Xms和 -Xmx: 使用-Xms=-Xmx 使堆不可调整大小,减少堆管理的问题。结合AlwaysPreTouch, -Xms=-Xmx 将在启动时提交所有内存,从而避免在最终使用内存时出现问题。-Xms还定义了内存未提交的低边界,因此使用-Xms=-Xmx, 所有内存都将保持提交。也就是说,如果您想配置 Shenandoah 以减少占用空间,则建议设置较低的-Xms。您需要决定将其设置为多低以平衡提交/取消提交开销与内存占用。在很多情况下,设置-Xms任意低就可以了。使用大页面极大地提高了大堆的性能。有两种方式可以选择加入。-XX:+UseLargePages将启用 Hugetlbfs (Linux) 或 Windows(具有适当的权限)支持。-XX:+UseTransparentHugePages将透明地启用它。对于透明大页面,建议将/sys/kernel/mm/transparenthugepage/enabled和/sys/kernel/mm/transparenthugepage/defrag 设置为"madvise"。使用 AlwaysPreTouch 运行时,它还将在启动时预先支付碎片整理费用。-XX:+UseNUMA:虽然 Shenandoah 尚不明确支持 NUMA,但启用它以在多套接字主机上启用 NUMA 交错是一个好主意。与 AlwaysPreTouch 相结合,它提供了比默认的开箱即用配置更好的性能-XX:-UseBiasedLocking:在无竞争(偏向)锁定吞吐量和 JVM 根据需要启用和禁用它们的安全点之间存在权衡。对于面向延迟的工作负载,关闭偏向锁定是有意义的。-XX:+DisableExplicitGC:从用户代码调用 System.gc() 强制 Shenandoah 执行额外的 GC 循环;禁用它以防止滥用 System.gc() 的代码可能是有益的。它通常不会受到影响,因为 -XX:+ExplicitGCInvokesConcurrent 默认启用,这意味着将调用并发 GC 周期,而不是 STW Full GC。八、结论

  本文解释了 Shenandoah GC 中的并发线程堆栈处理如何解决剩余垃圾收集暂停时间问题并在 JDK 17 中提供可靠的亚毫秒级垃圾收集暂停。要了解更多信息,请访问 Shenandoah GC 项目的 GitHub 存储库 和 OpenJDK Wiki 页面。

这篇关于OpenJDK 17 中的 Shenandoah:亚毫秒级 GC 停顿「译」的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/288042

相关文章

【编程底层思考】垃圾收集机制,GC算法,垃圾收集器类型概述

Java的垃圾收集(Garbage Collection,GC)机制是Java语言的一大特色,它负责自动管理内存的回收,释放不再使用的对象所占用的内存。以下是对Java垃圾收集机制的详细介绍: 一、垃圾收集机制概述: 对象存活判断:垃圾收集器定期检查堆内存中的对象,判断哪些对象是“垃圾”,即不再被任何引用链直接或间接引用的对象。内存回收:将判断为垃圾的对象占用的内存进行回收,以便重新使用。

17 通过ref代替DOM用来获取元素和组件的引用

重点 ref :官网给出的解释是: ref: 用于注册对元素或子组件的引用。引用将在父组件的$refs 对象下注册。如果在普通DOM元素上使用,则引用将是该元素;如果在子组件上使用,则引用将是组件实例: <!-- vm.$refs.p will be the DOM node --><p ref="p">hello</p><!-- vm.$refs.child will be the c

react笔记 8-17 属性绑定 class绑定 引入图片 循环遍历

1、绑定属性 constructor(){super()this.state={name:"张三",title:'我是一个title'}}render() {return (<div><div>aaaaaaa{this.state.name}<div title={this.state.title}>我是一个title</div></div></div>)} 绑定属性直接使用花括号{}   注

【全网最全】2024年数学建模国赛A题30页完整建模文档+17页成品论文+保奖matla代码+可视化图表等(后续会更新)

您的点赞收藏是我继续更新的最大动力! 一定要点击如下的卡片,那是获取资料的入口! 【全网最全】2024年数学建模国赛A题30页完整建模文档+17页成品论文+保奖matla代码+可视化图表等(后续会更新)「首先来看看目前已有的资料,还会不断更新哦~一次购买,后续不会再被收费哦,保证是全网最全资源,随着后续内容更新,价格会上涨,越早购买,价格越低,让大家再也不需要到处买断片资料啦~💰💸👋」�

算法练习题17——leetcode54螺旋矩阵

题目描述 给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。  代码 import java.util.*;class Solution {public List<Integer> spiralOrder(int[][] matrix) {// 用于存储螺旋顺序遍历的结果List<Integer> result = new ArrayList

标准库标头 <filesystem> (C++17)学习

此头文件是文件系统支持库的一部分。本篇介绍filesystem命名空间的一些函数。 函数 在命名空间 std::filesystem 定义 absolute (C++17) 组成一个绝对路径 (函数) canonicalweakly_canonical (C++17) 组成一个规范路径 (函数) relativeproximate (C++17) 组成一个相对路径 (函数) copy (C

C++基础:折叠表达式(C++17)

C++基础:折叠表达式(C++17) 简介语法展开 示例 简介 C++17 引入了一种新的语法特性,叫做折叠表达式,它允许编译器在模板参数包展开时进行元编程操作。折叠表达式的引入极大地简化了元编程代码,使其变得更为直观和简介。 语法 折叠表达式,简单来说,就是以二元运算符对形参包进行折叠,总共有以下四种类型: 一元右折叠一元左折叠二元右折叠二元左折叠 其对应的语法如下:

javaweb-day01-2(00:17:48 XML 的作用 和 语法)

XML: 描述 可扩展标记语言,w3c  2000年发布的 XML 1.0 版本规范。 用来描述数据之间的关系。 经常用作 软件  的配置文件,描述 模块与模块 之间的关系。 还用作    软件启动  的配置文件,描述 启动模块之间的 依赖 关系。 语法 一个XML文件分为如下几部分内容: 文档声明元素属性注释CDATA区、转义字符处

PostgreSQL 17即将发布,新功能Top 3

按照计划,PostgreSQL 17 即将在 2024 年 9 月 26 日发布,目前已经发布了第一个 RC 版本,新版本的功能增强可以参考 Release Notes。 本文给大家分享其中 3 个重大的新增功能。 MERGE 语句增强 MERGE 语句是 PostgreSQL 15 增加的一个新功能,它可以在单个语句中实现 INSERT、UPDATE 以及 DELETE 操作,非常适合数据

关于LLC知识17

1、如何判断一个元器件是不是源? 对于Lr,Lm,Cr这三个元器件,在工作过程中,能量是不断变化的,如果某个元器件的能量增大,说明它在充电,不是源,如果某个元器件的能量是在慢慢减小,说明是在放电就是一个源。 对于一个理想变压器来说,到副边始终是传输能量,能量是透传的,所以不存在充电和放电的问题。 2、判断透传电流正负的方法 Lm压差为上正下负时候,副边D1导通,副边从同名端出,原边也从