分代ZGC介绍

背景

在JDK 11中作为实验性功能推出的ZGC(JEP 333: ZGC: A Scalable Low-Latency Garbage Collector ),经过10个版本的迭代,终于在24年9月GA的JDK 23中将分代模式调整为默认模式(JEP 474: ZGC: Generational Mode by Default),版本趋于稳定并能够适配绝大多数实际生产场景。
本文将介绍ZGC分代回收机制和原理。

动机

在JAVA 30年的发展历程中,JVM提供了多种多样的垃圾回收器:

  • 串行垃圾回收器(Serial Collector):一种简单的垃圾回收器,它会暂停所有应用程序线程,适用于客户端类型的机器,但不适用于多线程服务器环境。
  • 并行垃圾回收器(Parallel Garbage Collector):在JDK5到JDK8中被使用,它是多线程环境下的一个不错选择。它使用多个线程来管理堆空间,但在执行垃圾回收时也会冻结其他应用程序。
  • CMS(Concurrent Mark Sweep):核心设计上较之前垃圾回收器更为复杂。它更倾向于较短的垃圾回收暂停时间,并且在应用程序运行时能够与垃圾回收器共享处理器资源。CMS的平均响应速度较慢,但不会暂停应用程序线程来执行垃圾回收操作。
  • G1(Garbage First Collector):CMS的替代产品,为拥有大内存空间的多处理器机器设计的,它将堆划分为多个Region,解决了CMS内存碎片化和回收暂停时间无法预先配置的问题。
  • ZGC(Z Garbage Collector):ZGC是一种并发的、分页的、支持NUMA的垃圾回收器,它使用coloured指针、load barriers和store barriers。其中coloured指针是 ZGC 的核心概念,ZGC使用指针中的某些高位来标记对象所处的GC阶段。ZGC能处理大小从 8MB 到 16TB 的堆内存范围。

JDK 21之前的ZGC是不支持分代的,直到JDK 21引入了JEP 439: Generational ZGC。不分代时,ZGC将所有对象存储在一起,无论年龄大小,ZGC必须在每次运行时扫描所有对象。
当服务器压力较大时,这极有可能导致内存回收速率跟不上应用申请内存速率,进而触发Allocation Stall,即线程粒度的分配暂停,应用线程直到可以重新申请新内存方可继续执行,极大的影响服务可用性。

而分代回收主要是基于两个假说:

  • 弱分代假说(Weak Generational Hypothesis):绝大多数对象是朝生暮死,在年轻时死亡。
  • 强分代假说(Strong Generational Hypothesis):熬过多次垃圾回收的老年对象往往难以死亡。
    因此,收集年轻对象消耗的资源较少,回收的内存较多;而收集老年对象消耗的资源较多,回收的内存较少。
    所以,我们可以通过更频繁地收集新生代对象来提高使用ZGC的资源利用和性能。

分代ZGC的设计

内存模型

分代ZGC将堆内存划分为两个逻辑区域:新生代和老年代。
新创建的对象通常分配在新生代,而如果对象能活过几次GC周期,则将被晋升到老年代。在分代ZGC中,新生代和老年代仅为逻辑划分,它们在虚拟内存空间中并不需要连续。
在这里插入图片描述

MinorGC和MajorGC

在这里插入图片描述

分代ZGC中,新生代、老年代和应用线程的执行是完全并发的。

分代ZGC中,分两类GC

  • Minor GC:仅回收新生代。
    • 初始标记阶段的根包含GC roots中指向新生代的引用和老年代的remembered sets。

在这里插入图片描述

  • Major GC:回收全堆,包括老年代和新生代。
    • 从GC roots扫描全堆。

[图片]

GC阶段

在这里插入图片描述

分代ZGC的GC阶段与ZGC的GC阶段类似,也分为3次STW和3次并发阶段。

  • 第一次STW,初始标记。该阶段从GC roots和老年代remembered set出发找到根集合直接引用的活跃对象,并将其入栈。
  • 第一个并发阶段,并发标记,将初始标记找到的对象作为根,深度遍历对象的成员变量进行标记。此阶段需要考虑引用关系变化导致的漏标记问题。
  • 第二次STW,再标记和并行标记,在标记任务结束后尝试终止标记动作,由于GC线程和应用线程并发执行,有可能在GC工作线程结束标记后,应用线程又有了新的引用关系,因此需要STW判断是否真的结束了对象标记,如果没有结束,则需要并行标记。
  • 第二次并发阶段,并发准备转移,并发选择待回收的页面,并发初始化待转移的页面,初始化Forwardding Table。
  • 第三次STW,转移根对象引用的对象。
  • 第三次并发阶段,并发转移,将对象移动到新页面。

核心机制

No multi-mapped memory(不再使用多重映射内存)

在这里插入图片描述

在不分代的ZGC中,通过指针中不同的标记位区分不同的虚拟空间,而这些不同标记位指向的不同的虚拟空间通过mmap映射到同一物理地址。coloured指针用于快速实现并发标记、转移和重定向。但是多重映射会导致在各种内存检测工具中,使用内存被计算为实际使用内存的3倍。
在这里插入图片描述

与不分代ZGC的4个颜色位相比,分代ZGC需要12个颜色位来标识不同的GC阶段,这显然不能用多重映射内存来实现了。
在这里插入图片描述

分代ZGC中使用了无色指针来解决这个问题:

  • 在load屏障中擦除颜色位,得到一个无色的指针。
    • 如上面两图所示,load屏障中相关实现相当简单,指针直接右移16位,即擦除了颜色。
/* 在x86_64架构下的示例 */
movq rax,0x10(rbx)
shrq rax,$address_shift
ja slow_path
  • 在store屏障中还原颜色位
    • 当往堆中存储一个对象引用时,检查此次存储是否是自上次垃圾回收阶段以来改字段的第一次存储,如是,则进入slow path以恢复颜色位。
testl Ox10(rbx), $store_bad_mask // 测试是否需要进入slow path
jnz slow_path
shlq rax, $address_shift // 左移
orq, rax, $colors // 修改颜色位
movq Ox10(rbx), rax
  • 不使用多重映射内存

无色指针的设计有不少优点:

  • 更大的可寻址的堆
  • 更多的颜色位
  • 不再有RSS、PSS的计算问题
  • 在x86_64和AArch64架构下,只用到了两条指令

load屏障和store屏障

当JVM从堆加载引用时,load屏障将在fast path中判断指针是否需要修复指针;如果需要,则放入slow path中修复它。
通常fast path是直接插入到JIT即时编译的应用程序代码中,而slow path逻辑相对复杂,为了便于维护,则由c++实现。

store屏障的slow path主要工作如下:

  • 并发的新生代SATB标记
  • 并发的老年代SATB标记
  • 并发维护remembered sets

SATB(Snapshot-at-beginning)

与非分代ZGC不同,分代ZGC采用了SATB机制,在标记开始阶段,GC对GC根进行快照,在标记结束时,确保标记了快照中所有可达对象。
因此,当对象引用关系中断时,内存屏障将要覆盖的引用值通知GC,然后GC将会标记引用的对象并标记从该对象字段上的引用。

记录集(remembered sets)

很多GC算法使用卡表来追踪从老年代到新生代的引用,通常卡表是一个大型byte数组,其中一位对应512字节的堆空间,如果老年代堆空间中的对象引用了新生代对象,则对应的卡表位设置为1。
G1则使用remembered set记录region之间的引用,每种不同的GC算法对于remembered set的具体实现均不同,分代ZGC使用位图精确对象位置。
另外分代ZGC有两个记录集,大约占用了3%的JVM内存消耗。

  • current remembered set,应用线程负责写入。线程执行过程中,当有新增的从老年代指向新生代的引用,则应用线程将引用信息写入记录集。
  • previous remembered set
    • 由GC线程负责扫描和清理。新生代标记开始时,交换current remembered set和previous remembered set。

两个记录集的好处在于,不需要引入新的内存屏障和内存可行性机制,也避免了GC线程和应用线程的竞争。

Dense heap regions

GC在进行新生代对象转移时,不同page中的存活对象数量和其占用的内存量均不同。分代ZGC将分析新生代page的内存使用情况和预计回收情况,以确定哪些page值得转移、哪些page转移成本较高。某些page可能会由于转移成本过高,而原地晋升为老年代。
这种整个page晋升老年代的机制,将减少回收新生代的压力。

性能提升

分代ZGC通过频繁的回收新生代内存,更加有效的利用了CPU资源。
吞吐量:分代ZGC的吞吐量比JDK17中的ZGC提升了10%左右。
在这里插入图片描述

暂停时间:分代ZGC的平均暂停时间较JDK17中的ZGC略有提升,但暂停时间P99分位值获得了极大改善,降低了约20%。
在这里插入图片描述

在这里插入图片描述

ZGC的未来规划

Thread local GC

  • 逃逸分析,识别出仅能被当前线程访问的对象。
  • 针对不能逃逸的对象,专门进行局部的垃圾回收。
  • 对CPU缓存机制更加友好。

总结

分代ZGC能够适用于绝大多数使用场景,
预计2025年3月发布的JDK 24中将移除ZGC的非分代模式(JEP 490: ZGC: Remove the Non-Generational Mode)。

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

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

相关文章

Flume基础概念

目录 作用组件构成ClientFlowAgentSourceSinkEvent 和Log4j的区别与定位事务传出流程输入到sourcesource端输入Channel 接收输入到SinkSink输出 作用 Flume可以从各种来源(如日志文件、消息队列、网络数据、文件系统、数据库等)收集数据,并将…

解决IDEA的easycode插件生成的mapper.xml文件字段之间逗号丢失

问题 easycode插件生成的mapper.xml文件字段之间逗号丢失,如图 解决办法 将easycode(在settings里面的othersettings)设置里面的Template的mapper.xml.vm和Global Config的mybatisSupport.vm的所有$velocityHasNext换成$foreach.hasNext Template的mapper.xml.vm(…

策略模式实战 - 猜拳游戏

**可以整体的替换一套算法,这就是策略模式。**这样对于同一个问题,可以有多种解决方案——算法实现的时候,可以通过策略模式来非常方便的进行算法的整体替换,而各种算法是独立封装好的,不用修改其内部逻辑。 具体的实…

漫画之家Spring Boot:漫画资源的个性化推荐

4 系统设计 4.1系统设计主要功能 通过市场调研及咨询研究,了解了用户及管理者的使用需求,于是制定了管理员和用户等模块。功能结构图如下所示: 图4-1系统功能结构图 4.2数据库设计 4.2.1数据库设计规范 数据可设计要遵循职责分离原则&#…

C++:AVL树

文章目录 一、AVL树的概念二、AVL树的实现1、AVL树的节点2、 AVL的插入的过程3、平衡因子的更新 三、旋转1、右单旋2、左单旋3、右左双旋4、右左双旋 四、AVL树平衡检测五、AVL树查找 一、AVL树的概念 二、AVL树的实现 1、AVL树的节点 key,vaule的二叉搜索树,需要…

Vscode插件 :用于生成文件头部注释和函数注释

最近找到了一个好用的vscode生成注释的插件----koroFileHeader 1.在拓展中搜索,并且安装 2.找到setting.json 设置模板 点击ctrlp(windows and linus),commandp(mac) 输入 > Open Settings 点击第一个选项 并且用以下代码进行覆盖 // 头部注释 "file…

知从科技闪耀汽车智能底盘大会:共探软件安全新篇章

在汽车科技蓬勃发展的浪潮中,智能底盘技术正成为引领行业变革的关键力量。11月27日-28日,盖世汽车 2024 第四届汽车智能底盘大会盛大召开,上海知从科技有限公司受邀出席此次盛会,与众多汽车领域的精英齐聚一堂,共话智能…

LabVIEW密码保护与反编译的安全性分析

在LabVIEW中,密码保护是一种常见的源代码保护手段,但其安全性并不高,尤其是在面对专业反编译工具时。理论上,所有软件的反编译都是可能的,尽管反编译不一定恢复完全的源代码,但足以提取程序的核心功能和算法…

ABAP 类与对象 EXCEPTIONS与RAISE

文章目录 ABAP 类与对象 EXCEPTIONS与RAISE系统示例代码执行结果RAISE的系统文档测试 ABAP 类与对象 EXCEPTIONS与RAISE 系统示例 代码 CLASS cls DEFINITION.PUBLIC SECTION.CLASS-METHODS meth EXCEPTIONS exc. ENDCLASS.CLASS cls IMPLEMENTATION.METHOD meth....RAISE ex…

接第二部分 Advanced Learning Algorithms

接第二部分 Advanced Learning Algorithms 文章目录 接第二部分 Advanced Learning AlgorithmsMachine learning development process(机器学习开发的迭代)Iterative loop of ML development错误分析(error analysis)添加数据(Adding data)迁移学习:使用其他任务中的…

AI新动向:豆包文生图升级,文心一言领先市场

在今日的AI资讯中,我们关注到了几个重要的行业动态,其中包括字节跳动AI助手豆包的功能升级,以及百度文心一言在生成式AI市场的领先地位。 字节跳动旗下的智能AI助手豆包近期对其文生图能力进行了显著提升,用户现在可以通过一键操…

力扣54.螺旋矩阵

题目描述 题目链接54. 螺旋矩阵 给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。 示例 1: 输入:matrix [[1,2,3],[4,5,6],[7,8,9]] 输出:[1,2,3,6,9,8,7,4,5]示例 2:…

【第 1 章 初识 C 语言】1.10 - 1.11 本书的组织结构、本书的约定

目录 1.10 本书的组织结构 1.11 本书约定 1.11.1 字体 1.11.2 程序输出 特殊的击键 本书使用的系统 读者的系统 1.11.3 特殊元素 1.10 本书的组织结构 本书采用多种方式编排内容,其中最直接的方法是介绍 A 主题的所有内容、介绍 B 主题的所有内容&#xff0…

# 06_Python基础到实战一飞冲天(三)-python面向对象(六)--类属性和类方法和单例

06_Python基础到实战一飞冲天(三)-python面向对象(六)–类属性和类方法和单例 一、类属性-05-使用对象名类属性赋值语句会创建实例属性 1、使用对象名访问类属性的问题注意 如果使用 对象.类属性 值 赋值语句,只会…

【目标跟踪】DUT Anti-UAV数据集详细介绍

DUT Anti-UAV数据集是大连理工大学的团队公开的数据集(DUT是他们学校的简称),其中包括了两个子数据集:目标检测和目标跟踪(也就是说,目标检测和目标跟踪都可以用这个数据集)。该数据集为可见光模…

★ 数据结构 ★ 排序

Ciallo&#xff5e;(∠・ω< )⌒☆ ~ 今天&#xff0c;我将和大家一起学习数据结构中的各种排序~ ​❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️ 澄岚主页&#xff1a;椎名澄嵐-CSDN博客 数据结构专栏&#xff1a;https://blog.csdn.net/2302_80328146/categ…

c语言基础三:运算符和表达式

一、常用的运算符分类 运算符类型 作用 算术运算符 用于处理四则运算 赋值运算符 用于将表达式的值赋给变量 比较运算符 用于表达式的比较&#xff0c;并返回一个真值或假值 逻辑运算符 用于根据表达式的值返回真值或假值 位运算符 用于处理数据的位运算 s…

如何通过金蝶云星空高效集成销售出库单

金蝶云星空数据集成案例分享&#xff1a;销售出库单-&#xff08;分销&京东&唯品&虚拟除外&#xff09;手表汇总 在企业信息化系统中&#xff0c;数据的高效流转和准确对接是业务运作的关键。本文将聚焦于一个具体的系统对接集成案例&#xff0c;即如何将金蝶云星…

【SKFramework框架核心模块】3-4、事件模块

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享QQ群&#xff1a;398291828小红书小破站 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 【Unity3D框架】SKFramework框架完全教程《全…

鸿蒙分享:添加模块,修改app名称图标

新建公共模块common 在entry的oh-package.json5添加dependencies&#xff0c;引入common模块 "dependencies": {"common": "file:../common" } 修改app名称&#xff1a; common--src--resources--string.json 新增&#xff1a; {"name&q…