JVM原理之详解现代垃圾回收器 Shenandoah 和 ZGC

news2024/11/24 14:14:07

Shenandoah

Shenandoah 一词来自于印第安语,十九世纪四十年代有一首著名的航海歌曲在水手中广为流传,讲述一位年轻富商爱上印第安酋长 Shenandoah 的女儿的故事。 后来美国有一条位于 Virginia 州西部的小河以此命名,所以 Shenandoah 的中文译名为 “情人渡”。

Shenandoah 首次出现在 Open JDK12 中,是由 Red Hat 开发,主要为了解决之前各种垃圾回收器处理大堆时停顿较长的问题。

相比较 G1 将低停顿做到了百毫秒级别,Shenandoah 的设计目标是将停顿压缩到 10ms 级别,且与堆大小无关。它的设计非常激进,很多设计点在权衡上更倾向于低停顿,而不是高吞吐。

“G1 的继承者”

Shenandoah 是 OpenJDK 中的垃圾处理器,但相比较 Oracle JDK 中根正苗红的 ZGC,Shenandoah 可以说更像是 G1 的继承者,很多方面与 G1 非常相似,甚至共用了一部分代码。

总的来说,Shenandoah 和 G1 有三点主要区别:

1.G1 的回收是需要 STW 的,而且这部分停顿占整体停顿时间的 80% 以上,Shenandoah 则实现了并发回收。

2.Shenandoah 不再区分年轻代和年老代。

3.Shenandoah 使用连接矩阵替代 G1 中的卡表。

关于 G1 的详细介绍请翻看前一篇:从原理聊 JVM(二):从串行收集器到分区收集开创者 G1

连接矩阵(Connection Matrix)

G1 中每个 Region 都要维护卡表,既耗费计算资源还占据了非常大的内存空间,Shenandoah 使用了连接矩阵来优化了这个问题。

连接矩阵可以简单理解为一个二维表格,如果 Region A 中有对象指向 Region B 中的对象,那么就在表格的第 A 行第 B 列打上标记。

比如,Region 1 指向 Region 3,Region 4 指向 Region 2,Region 3 指向 Region 5:

相比 G1 的记忆集来说,连接矩阵的颗粒度更粗,直接指向了整个 Region,所以扫描范围更大。但由于此时 GC 是并发进行的,所以这是通过选择更低资源消耗的连接矩阵而对吞吐进行妥协的一项决策。

转发指针

转发指针的性能优势

想要达到并发回收,就需要在用户线程运行的同时,将存活对象逐步复制到空的 Region 中,这个过程中就会在堆中同时存在新旧两个对象。那么如何让用户线程访问到新对象呢?

此前,通常是在旧对象原有内存上设置保护陷阱(Memory Protection Trap),当访问到这个旧对象时就会发生自陷异常,使程序进入到预设的异常处理器中,再由处理器中的代码将访问转发到复制后的新对象上。

自陷是由线程发起来打断当前执行的程序,进而获得 CPU 的使用权。这一操作通常需要操作系统参与,那么就会发生用户态到内核态的转换,代价十分巨大。

所以 Rodney A.Brooks 提出了使用转发指针来实现通过旧对象访问新对象的方式:在对象头前面增加一个新的引用字段,在非并发移动情况下指向自己,产生新对象后指向新对象。那么当访问对象的时候,都需要先访问转发指针看看其指向哪里。虽然和内存自陷方案相比同样需要多一次访问转发的开销,但是前者消耗小了很多。

转发指针的问题

转发指针主要存在两个问题:修改时的线程安全问题和高频访问的性能问题

1. 对象体增加了一个转发指针,这个指针的修改和对象本身的修改就存在了线程安全问题。如果通过被访问就可能发生复制了新对象后,转发对象修改之前发生了旧对象的修改,这就存在两个对象不一致的问题了。对于这个问题,Shenandoah 是通过 CAS 操作来保证修改正确性的。

2. 转发指针的加入需要覆盖所有对象访问的场景,包括读、写、加锁等等,所以需要同时设置读屏障和写屏障。尤其读操作相比单纯写操作出现频率更高,这样高频操作带来的性能问题影响巨大。所以 Shenandoah 在 JDK13 中对此进行了优化,将内存屏障模型改为引用访问屏障,也就是说,仅仅在对象中引用类型的读写操作增加屏障,而不去管原生对象的操作,这就省去了大量的对象访问操作。

Shenandoah 的运行步骤

  1. 初始标记(Init Mark)[STW] [同 G1]

标记与 GC Roots 直接关联的对象。

  1. 并发标记(Concurrent Marking)[同 G1]

遍历对象图,标记全部可达对象。

  1. 最终标记(Final Mark)[STW] [同 G1]

处理剩余的 SATB 扫描,并在这个阶段统计出回收价值最高的 Region,将这些 Region 构成一组回收集。

  1. 并发清理(Concurrent Cleanup)

回收所有不包含任何存活对象的 Region(这类 Region 被称为 Immediate Garbage Region)。

  1. 并发回收(Concurrent Evacuation)

将回收集里面的存货对象复制到一个其他未被使用的 Region 中。并发复制存活对象,就会在同一时间内,同一对象在堆中存在两份,那么就存在该对象的读写一致性问题。Shenandoah 通过使用转发指针将旧对象的请求指向新对象解决了这个问题。这也是 Shenandoah 和其他 GC 最大的不同。

  1. 初始引用更新(Init Update References)[STW]

并发回收后,需要将所有指向旧对象的引用修正到新对象上。这个阶段实际上并没有实际操作,只是设置一个阻塞点来保证上述并发操作均已完成。

  1. 并发引用更新(Concurrent Update References)

顺着内存物理地址线性遍历堆空间,更新并发回收阶段复制的对象的引用。

  1. 最终引用更新(Final Update References)[STW]

堆空间中的引用更新完毕后,最后需要修正 GC Roots 中的引用。

  1. 并发清理(Concurrent Cleanup)

此时回收集中 Region 应该全部变成 Immediate Garbage Region 了,再次执行并发清理,将这些 Region 全部回收。

ZGC

ZGC 是 Oracle 官方研发并 JDK11 中引入,并于 JDK15 中作为生产就绪使用,其设计之初定义了三大目标:

1. 支持 TB 级内存

2. 停顿控制在 10ms 以内,且不随堆大小增加而增加

3. 对程序吞吐量影响小于 15%

随着 JDK 的迭代,目前 JDK16 及以上版本,ZGC 已经可以实现不超过 1 毫秒的停顿,适用于堆大小在 8MB 到 16TB 之间。

ZGC 的内存布局

ZGC 和 G1 一样也采用了分区域的堆内存布局,不同的是,ZGC 的 Region(官方称为 Page,概念同 G1 的 Region)可以动态创建和销毁,容量也可以动态调整。

ZGC 的 Region 分为三种:

1. 小型 Region 容量固定为 2MB,用于存放小于 256KB 的对象。

2. 中型 Region 容量固定为 32MB,用于存放大于等于 256KB 但不足 4MB 的对象。

3. 大型 Region 容量为 2MB 的整数倍,存放 4MB 及以上大小的对象,而且每个大型 Region 中只存放一个大对象。由于大对象移动代价过大,所以该对象不会被重分配。

重分配集(Relocation Set)

G1 中的回收集用来存放所有需要 G1 扫描的 Region,而 ZGC 为了省去卡表的维护,标记过程会扫描所有 Region,如果判定某个 Region 中的存活对象需要被重分配,那么就将该 Region 放入重分配集中。

通俗的说,如果将 GC 分为标记和回收两个主要阶段,那么回收集是用来判定标记哪些 Region,重分配集用来判定回收哪些 Region

染色指针

和 Shenandoah 相同,ZGC 也实现了并发回收,不同的是前者是使用转发指针来实现的,后者则是采用染色指针的技术来实现。

三色标记本质上与对象无关,仅仅与引用有关:通过引用关系判定对像存活与否。HotSpot 虚拟机中不同垃圾回收器有着不同的处理方式,有些是标记在对象头中,有些是标记在单独的数据结构中,而 ZGC 则是直接标记在指针上。

64 位机器指针是 64 位,Linux 下 64 位中高 18 位不能用来寻址,剩下 46 位中,ZGC 选择其中 4 位用来辅助 GC 工作,另外 42 位能够支持最大内存为 4T,通常来说,4T 的内存完全够用。

具体来说,ZGC 在指针中增加了 4 个标志位,包括 FinalizableRemappedMarked 0 和 Marked 1

源码注释如下:

 6                 4 4 4  4 4                                             0
 3                 7 6 5  2 1                                             0
+-------------------+-+----+-----------------------------------------------+
|00000000 00000000 0|0|1111|11 11111111 11111111 11111111 11111111 11111111|
+-------------------+-+----+-----------------------------------------------+
|                   | |    |
|                   | |    * 41-0 Object Offset (42-bits, 4TB address space)
|                   | |
|                   | * 45-42 Metadata Bits (4-bits)  0001 = Marked0
|                   |                                 0010 = Marked1
|                   |                                 0100 = Remapped
|                   |                                 1000 = Finalizable
|                   |
|                   * 46-46 Unused (1-bit, always zero)
|
* 63-47 Fixed (17-bits, always zero)

Finalizable 标识表示对象是否只能通过 finalize() 方法访问到,RemappedMarked 0 和 Marked 1 用作三色标记(后面简称为 M0 和 M1)。

为什么既有 M0 还有 M1 呢?

因为 ZGC 标记完成后并不需要等待对象指针重映射就可以进行下一次垃圾回收循环,也就是说两次垃圾回收的全过程是有重叠的,所以使用两个标记位分别用作两次相邻 GC 过程的标记,M0 和 M1 交替使用。

染色指针的在 GC 过程中的作用

我们通过红蓝黄三个颜色分别表示三种标记状态:

1. 第一次标记开始时所有的指针都处于 Remapped 状态

  1. 从 GC Root 开始,顺着对象图遍历扫描,存活对象标记为 M0

  1. 标记完成后,开始进行并发重分配。最终目标是将 A、B、C 三个存活对象都移动到新的 Region 中去。

整个标记过程中新分配到对象都被直接标记为 M0,比如对象 D。

复制完成的对象,指针就可以由 M0 改为 Remapped,并将旧对象到新对象到映射关系保存到转发表中。

  1. 如果此时系统访问对象 C,会触发读屏障,将原引用修正到新的对象 C 的地址上去,并转发访问,最后删除转发表的记录。

这个行为称为指针的 “自愈”。

实际上,如果没有对象 D 的存在,在上一步所有存货对象转移完成后,旧的 Page 就可以被回收了,依靠指针和转发表就可以将所有访问转发到新的 Page 中去。

  1. 并发重映射阶段会把所有引用修正,并删除转发表的记录。

  1. 下一次并发标记开始后,由于上一次垃圾回收循环并没有完成,所以 Remapped 指针被标记为 M1,用来和上一次的存活对象标记作区分。

可以看出,并发标记的过程中,ZGC 是通过读屏障来保证访问的正确转发,并且由于染色指针采用惰性更新的策略,相比 Shenandoah 每次都要先访问转发指针的两次寻址来说快上不少。

染色指针的三大优点

1. 由于染色指针提供的 “自愈” 能力,当某个 Page 被清除后可以立刻被回收,而无需等待修正全部指向该 Page 的引用。

2.ZGC 完全不需要使用写屏障,原因有二:由于使用染色指针,无需更新对象体;没有分代所以无需记录跨代引用。

3. 染色指针并未完全开发使用,剩下的 18 位提供了非常大的扩展性。

而染色指针有一个天然的问题,就是操作系统和处理器并不完全支持程序对指针的修改。

多种内存映射

染色指针只是 JVM 定义的,操作系统、处理器未必支持。为了解决这个问题,ZGC 在 Linux/x86-64 平台上采用了虚拟内存映射技术。

ZGC 为每个对象都创建了三个虚拟内存地址,分别对应 RemappedMarked 0 和 Marked 1,通过指针指向不同的虚拟内存地址来表示不同的染色标记。

分代

ZGC 没有分代,这一点并不是技术权衡,而是基于工作量的考虑。所以目前来看,整体的 GC 效率还有很大提升空间。

读屏障

ZGC 使用了读屏障来完成指针的 “自愈”,由于 ZGC 目前没有分代,且 ZGC 通过扫描所有 Region 来省去卡表使用,所以 ZGC 并没有写屏障,这成为 ZGC 一大性能优势。

NUMA

多核 CPU 同时操作内存就会发生争抢,现代 CPU 把内存控制系统器集成到处理器内核中,每个 CPU 核心都有属于自己的本地内存。

在 NUMA 架构下,ZGC 会有现在自己的本地内存上分配对象,避免了内存使用的竞争。

在 ZGC 之前,只有 Parallet Scavenge 支持 NUMA 内存分配。

ZGC 的运行步骤

ZGC 和 Shenadoah 一样,几乎所有运行阶段都和用户线程并发进行。其中同样包含初始标记、重新标记等 STW 的过程,作用相同,不再赘述。重点介绍以下四个并发阶段:

并发标记

并发标记阶段和 G1 相同,都是遍历对象图进行可达性分析,不同的是 ZGC 的标记在染色指针上。

并发预备重分配

在这个阶段,ZGC 会扫描所有 Region,如果哪些 Region 里面的存活对象需要被分配的新的 Region 中,就将这些 Region 放入重分配集中。

此外,JDK12 后 ZGC 的类卸载和弱引用的处理也在这个阶段。

并发重分配

ZGC 在这个阶段会将重分配集里面的 Region 中的存货对象复制到一个新的 Region 中,并为重分配集中每一个 Region 维护一个转发表,记录旧对象到新对象的映射关系。

如果在这个阶段用户线程并发访问了重分配过程中的对象,并通过指针上的标记发现对象处于重分配集中,就会被读屏障截获,通过转发表的内容转发该访问,并修改该引用的值。

ZGC 将这种行为称为自愈(Self-Healing),ZGC 的这种设计导致只有在访问到该指针时才会触发一次转发,比 Shenandoah 的转发指针每次都要转发要好得多。

另一个好处是,如果一个 Region 中所有对象都复制完毕了,该 Region 就可以被回收了,只要保留转发表即可。

并发重映射

最后一个阶段的任务就是修正所有的指针并释放转发表。

这个阶段的迫切性不高,所以 ZGC 将并发重映射合并到在下一次垃圾回收循环中的并发标记阶段中,反正他们都需要遍历所有对象。

总结

现代的垃圾回收器为了低停顿的目标可谓将 “并发” 二字玩到极致,Shenandoah 在 G1 基础上做了非常多的优化来使回收阶段并行,而 ZGC 直接采用了染色指针、NUMA 等黑科技,目的都是为了让 Java 开发者可以更多的将精力放在如何使用对象让程序更好的运行,剩下的一切交给 GC,我们所做的只需享受现代化 GC 技术带来的良好体验。

IDEA 保姆级安装教程:  http://note.youdao.com/s/Wq2GSETJ  

计算机专业常用毕业设计集合:  http://note.youdao.com/s/PIJHOqnk  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/490723.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【图像分割】【深度学习】SAM官方Pytorch代码-各模块的功能解析

【图像分割】【深度学习】SAM官方Pytorch代码-各功能模块解析 Segment Anything:建立了迄今为止最大的分割数据集,在1100万张图像上有超过1亿个掩码,模型的设计和训练是灵活的,其重要的特点是Zero-shot(零样本迁移性)转移到新的图…

mysql数据库高级操作

文章目录 一、克隆表1.方法一2.方法二 二、清空表,删除表内所有数据1.方法一2.方法二3.drop、truncate、delete对比 三、创建临时表四、用户管理五、忘记root密码的解决措施六、用户授权总结 一、克隆表 1.方法一 ​create table 新表名 like 复制的表名; ​ ​复…

如何应用PreMaint预测性维护助力企业节能减排

随着全球能源资源的日益减少和环境的变化,各行各业都在积极探索节能降耗的方法,以减少能源消耗和环境污染。而在工厂生产过程中,设备的稳定运行是节能降耗的关键。设备健康管理软件在这方面的应用,对于提高工厂的节能降耗效果具有…

NSSCTF之Misc篇刷题记录⑧

NSSCTF之Misc篇刷题记录 [MMACTF 2015]welcome[虎符CTF 2022]Plain Text[SWPUCTF 2021 新生赛]原来你也玩原神[SWPUCTF 2021 新生赛]我flag呢? NSSCTF平台:https://www.nssctf.cn/ PS:记得所有的flag都改为NSSCTF [MMACTF 2015]welcome NSS…

MySQL MVCC 机制

什么是mvcc mvcc(多版本并发控制),作用在于可无锁实现隔离级别中的“可重复读” 提高数据库关于事务处理上的性能问题,其中"多版本" 指的是 UndoLog 链中的多个事务,“控制” 指的是我当前应当读取那个事务id对应的数据…

「STC8A8K64D4开发板」——外部中断(INT0~INT4)

第2-4讲:外部中断(INT0~INT4) 学习目的学习中断的相关概念。掌握外部中断配置及中断优先级配置的程序设计。掌握中断服务程序的编写。 中断相关概念 什么是中断 中断系统是为使 CPU 具有对外界紧急事件的实时处理能力而设置的。 CPU在处理某一事件A时&#xff0c…

面试题30天打卡-day19

1、TCP 和 UDP 协议有什么区别,分别适用于什么场景? TCP(Transmission Control Protocol)和UDP(User Datagram Protocol)是两种常用的传输层协议,两者的区别比较如下: TCPUDP可靠性…

数据库初认识之MySQL

关系型数据库 数据结构 二维表格 库 -> 表 -> 列(字段):用来描述对象的一个属性 行(记录):用来描述一个对象的信息 Mysql(5.7/8.0) …

2023百度强引百度蜘蛛方法(百度蜘蛛秒引工具)

当谈到SEO时,关键字是最基本的元素之一。使用正确的关键字可以帮助您的网站在搜索引擎结果页面(SERP)中排名更高。在本篇文章中,我们将重点介绍2023年百度强引百度蜘蛛方法和百度蜘蛛秒引工具,并提供一些有用的SEO技巧…

比特米盒子刷安卓ATV6.0

最近海鲜市场有很多比特米盒子,50多块包邮,买来的盒子回来折腾下,买回来发现一直卡在“系统启动"中无法进入,不知道原来的是啥系统,看来只能找找线刷的办法,重新拯救救个这盒子。 原文链接地址&#x…

windows 下配置ssh 秘钥到souretree进行使用

一、准备工作 1、安装好git 客户端 并配置好环境变量 下载后,按照向导一步一步进行操作即可,具体步骤这里就不再进行说明。 注意:配置环境变量。 2、准备生成好SSH 秘钥文件 (默认文件名:id_rsa.rsa) &a…

【Ubuntu18.04使用yolov5教程】

欢迎大家阅读2345VOR的博客【Ubuntu18.04使用yolov5教程】🥳🥳🥳2345VOR鹏鹏主页: 已获得CSDN《嵌入式领域优质创作者》称号👻👻👻,座右铭:脚踏实地,仰望星空…

[LeetCode周赛复盘] 第 343 场周赛20230430

[LeetCode周赛复盘] 第 343 场周赛20230430 一、本周周赛总结2660. 保龄球游戏的获胜者1. 题目描述2. 思路分析3. 代码实现 2661. 找出叠涂元素1. 题目描述2. 思路分析3. 代码实现 2662. 前往目标的最小代价1. 题目描述2. 思路分析3. 代码实现 2663. 字典序最小的美丽字符串1.…

优化Google Cloud Storage大文件上传和内存溢出

背景 我们的项目每天都会并行上传好几万份文件到下游的GCP Cloud Storage,当文件比较大时,会采用GCP的可续上传方案,通过把文件切分成多个数据块,分多次HTTP请求上传到GCP Bucket,具体可参考https://cloud.google.com…

560. 和为 K 的子数组【哈希、前缀和】

560. 和为 K 的子数组 给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的连续子数组的个数 。 示例 1: 输入:nums [1,1,1], k 2 输出:2 示例 2: 输入:nums [1,2,3], k 3 输出&…

智能座舱3.0阶段,看全球巨头如何打造更具“价值”的第三空间

面向中国这一全球最大的汽车电动化与智能化单一市场,作为全球第七大汽车技术供应商的FORVIA佛瑞亚集团开始全面发力。 在2023年上海国际车展上,FORVIA佛瑞亚携旗下佛吉亚与海拉一系列突破性技术和互动体验亮相,展示了对电气化与能源管理、安…

SpringMVC详细介绍和@RequestMapping详细使用说明

目录 SpringMVC SpringMVC 介绍 说明是 MVC MVC 全称∶ Model 模型、View 视图、 Controller 控制器。 MVC 是一种思想 MVC 示意图 理解和解读 SpringMVC 特点&概述 梳理 Spring SpringMVC SpringBoot 的关系 SpringMVC-快速入门 SpringMVC 登录流程分析 SpringM…

OpenGL学习教程之 材质

材质 在真实世界里,每个物体会对光产生不同的反应。钢看起来比陶瓷花瓶更闪闪发光,一个木头箱子不会像钢箱子一样对光产生很强的反射。每个物体对镜面高光也有不同的反应。有些物体不会散射(Scatter)很多光却会反射(Reflect)很多光,结果看起来…

Wireshark的安装及基本使用【计算机网络】

Wireshark的安装与基本使用【计算机网络】 前言推荐Wireshark的安装与基本使用一、下载二、安装三、使用技巧四、简单使用4.1 捕获4.2 简单介绍4.3 过滤 问题 最后 前言 2023-5-4 20:51:42 以下内容源自《【计算机网络】》 仅供学习交流使用 推荐 Wireshark的下载安装及简单…

macOS 13.4Beta 4(22F5059b)With OpenCore 0.9.2开发版 and winPE双引导分区原版镜像

镜像特点 完全由黑果魏叔官方制作,针对各种机型进行默认配置,让黑苹果安装不再困难。系统镜像设置为双引导分区,全面去除clover引导分区(如有需要,可以自行直接替换opencore分区文件为clover引导文件)备注…