分代ZGC详解

news2024/11/18 15:53:39

ZGC(Z Garbage Collector)是Java平台上的一种垃圾收集器,它是由Oracle开发的,旨在解决大堆的低延迟垃圾收集问题。ZGC是一种并发的分代垃圾收集器,它主要针对具有大内存需求和低停顿时间要求的应用程序

分代ZGC收集器具备以下特性:

  • 没有多重映射内存
  • 内存屏障优化
  • 双重缓冲记忆集
  • 无需额外堆内存重分配
  • 堆区域密度
  • 大对象处理

核心概念

染色指针

染色指针是指向堆中对象的指针,该对象与对象的内存地址一起包含对对象的已知状态进行编码的元数据。元数据描述了对象是否已知是活动的、地址是否正确等等。

分代ZGC染色指针布局

在分代 ZGC 中,存储在对象字段中的对象引用被实现为染色指针。然而,存储在 JVM 堆栈中的对象引用在硬件堆栈或 CPU 寄存器中实现为无色指针,没有元数据位。读屏障和存储屏障控制染色指针和无色指针之间的转换。

由于染色指针永远不会出现在硬件堆栈或 CPU 寄存器中,因此只要可以有效地完成染色指针和无色指针之间的转换,就可以使用更奇特的染色指针布局

Generational ZGC 使用的染色指针布局将元数据放在指针的低位中,将对象地址放在高位中,这最大限度地减少了负载屏障中的机器指令数量。通过仔细编码内存地址和元数据位,单个移位指令(在 x64上)既可以检查指针是否需要处理,也可以删除元数据位。

GC 阶段标记

非分代 ZGC 判断指针处于哪一个GC阶段很简单,只需要简单的位移:

movq  rax, 0x10(rbx)
testq rax, 0x20(r15)
jnz   slow_path

testq即等价于&操作,是一般的 bitflag 做法

分代 ZGC 的代码是这样的:

movq rax, 0x10(rbx)
shrq rax, $address_shift
ja   slow_path

shrq 是右移操作,同时会设置 Carry Flag 为最后移除的一位,同时如果右移的结果为 0,Zero Flag 也会被设为 0。

ja是 jump if above 指令,仅在CF == 0 && ZF == 0时跳转

该指令的操作过程可以见下图

分代 ZGC 加载屏障示意图

每次加载均会将地址右移,同时由于 8 字节对齐,JVM 保证了最低三位的值一定为 0,因此若该指针被更新(最后被移除的位值为 1),则会跳入 slow path 分支处理下一个 GC 阶段

最大堆大小

对于64位系统,ZGC支持最大堆大小:JDK11(4TB) -> JDK15(16TB) -> JDK21(16TB+)

JDK 15 ZGC对象指针

在64位的Linux操作系统中,高18位(或称为高16TB)是由内核保留的,在用户空间是无法直接寻址的。JDK15中使用了其中两位作为标志位

HotSpot虚拟机的标记实现方案

  • Serial: 标记记录在对象头上
  • G1/Shenandoah: 标记记录在与对象相互独立的数据结构(BitMap)上
  • ZGC: 标记信息记在引用对象的指针上

多重映射内存

分代ZGC不再使用多重映射内存

内存多重映射(Multi-Mapping)将多个不同的虚拟内存地址映射到同一个物理内存地址上,是一种多对一映射

内存屏障

由于分代 ZGC 的元数据比较多,使用多重映射内存的方法不再能行得通。因此,在寄存器和栈中的内存地址需要为普通的无色指针。分代 ZGC 不再能通过此减少加载或存储内存屏障的开销,需要在有色和无色指针之间转换,即:

  • 加载屏障: 在加载时移除元数据
  • 存储屏障: 在存储时恢复元数据

用于优化屏障的一些技术是:

  • 快路径和慢路径
  • 最小化加载屏障职责
  • 记忆集屏障
  • SATB 标记屏障
  • 混合存储屏障检查
  • 存储屏障缓冲区
  • 屏障修补

快路径和慢路径

快路径检测是否需要额外的 GC 工作,当需要时,会跳转进入慢路径,开始相关工作。快路径由 JIT 实现,会直接插入 GC 代码至 JIT 编译后的程序。而慢路径不经常调用,所以使用 C++ 实现

最小化加载屏障职责

分代 ZGC 中,我们需要监控年轻代和老年代,并且在有色指针和无色指针间转换。为了简化加载屏障的复杂性,并引入优化加载屏障的空间,标记的职责交给了加载屏障

在分代 ZGC 中,加载屏障负责:

  • 转换有色指针为无色指针
  • 更新已被 GC 更新的过时指针

存储屏障负责:

  • 转换无色指针为有色指针
  • 维护记忆集
  • 标记对象存活

记忆集和 SATB

记忆集和SATB的概念与G1中一致,详细可见G1 垃圾收集器详解

存储屏障缓冲区

将障碍分为快速路径和慢速路径,并使用指针着色,可以减少对 C++ 慢速路径函数的调用次数。

分代 ZGC 通过在快速路径和慢速路径之间放置 JIT 编译的中间路径来进一步减少开销。中间路径将要覆盖的值和对象字段的地址存储在存储屏障缓冲区中,并返回到已编译的应用程序代码,而不需要采取昂贵的慢速路径。仅当存储屏障缓冲区已满时才采用慢速路径。这可以分摊从编译的应用程序代码转换到 C++ 慢路径代码的一些开销

双重缓冲记忆集

ZGC 的记忆集不使用卡表实现,而是由两个 bitmap 实现。一个 bitmap 用于用户线程,在加载屏障中修改,另一个只读的 bitmap 用于 GC。这样做有两个好处:

  • 用户线程无需等待 bitmap 被清除
  • 因为分了两个 bitmap,所以不需要额外的内存屏障,造成额外的内存开销

无需多余堆空间的重分配

其他 HotSpot GC 中的年轻代回收使用清理模型,GC 一次性找到存活对象并重分配。在 GC 完全了解哪些对象还活着之前,年轻代中的所有对象都必须重分配,在这之后才能回收内存。因此,这些 GC 需要猜测存活对象所需的内存量,并确保在 GC 启动时该内存量可用。如果猜错了,则需要更昂贵的清理操作:例如,就地固定未重分配的对象,这会导致内存碎片,或者 Full GC。

分代 ZGC 有两个阶段:

  1. 访问并标记所有可达对象
  2. 重分配标记的对象

由于 GC 在重分配之前就知道对象是否存活,因此可以按区域粒度划分工作。一旦存活对象都被重分配出某个区域,即该区域已被清除,该区域就被当作新的目标区域,继续用于重分配或被应用使用。即使没有额外的堆空间,ZGC 仍可通过将压缩对象到当前区域来继续重分配。这使得分代 ZGC 能够重分配并压缩年轻代,而无需使用额外的堆内存

堆区域密度

如果一个区域的存活对象很多,将它们一个个移到老年代堆的操作是不值得的。ZGC 会分析年轻代存活对象的密度,以此为一句来判断是否有机会就地升级为老年代。否则,这个区域会保留为年轻代

大对象处理

ZGC 已经可以很好地处理大型对象。通过将虚拟内存与物理内存解耦,并提前保留虚拟内存,大对象的碎片问题通常可以避免

在分代 ZGC 中,允许在年轻代中分配大对象。鉴于该区域现在可以在不重分配的情况下老化,因此不再需要在老一代中分配大对象。相反,如果大对象寿命较短,则可以在年轻代中收集它们;如果寿命较长,则可以廉价地将它们提升到老年代。

ZGC JVM参数

ZGC 通用参数

参数描述默认值
-XX:MinHeapSize, -Xms最小堆大小8M
-XX:InitialHeapSize, -Xms初始化堆大小128M
-XX:MaxHeapSize, -Xmx最大堆大小2036M
-XX:SoftMaxHeapSizeJVM堆的最大软限制2036M
-XX:ConcGCThreads并发GC的线程数量1
-XX:ParallelGCThreads设置垃圾回收时的并行GC线程数量4
-XX:UseLargePages使用大页面内存false
-XX:UseTransparentHugePages使用Transparent大页面内存
-XX:UseNUMA使用UNMA内存分配,可以获得更好的性能
-XX:SoftRefLRUPolicyMSPerMB每MB的空闲内存空间允许软引用对象存活时间1000
-XX:AllocateHeapAt堆分配参数,可以使用非DRAM 内存

ZGC 特有参数

参数描述默认值
-XX:ZAllocationSpikeTolerance修正系数,数值越大,越早触发GC2.000000
-XX:ZCollectionIntervalZGC发生的最小时间间隔,单位秒0.000000
-XX:ZFragmentationLimitrelocation时,当前region碎片化大于此值,则回收region25.000000
-XX:ZMarkStackSpaceLimit指定为标记堆栈分配的最大字节数8096M
-XX:ZProactive是否启用主动回收true
-XX:ZUncommit是否归还不使用的内存给OStrue
-XX:ZUncommitDelay不再使用的内存最多延迟多久会归还给OS300s

ZGC 诊断选项

通过-XX:+UnlockDiagnosticVMOptions开启诊断选项

参数描述
-XX:+UnlockDiagnosticVMOptions使用诊断模式,下面的参数才会起作用
-XX:ZStatisticsInterval指定统计数据输出之间的时间间隔(秒)
-XX:ZVerifyForwarding检验转发表
-XX:ZVerifyMarking检验标记集
-XX:ZVerifyObjects检验对象
-XX:ZVerifyRoots检验根节点
-XX:ZVerifyViews检验堆视图访问

分代ZGC 特有参数

参数描述
-XX:ZCollectionIntervalMinorZGC进行年轻代垃圾收集(MinorGC)的时间间隔(秒)
-XX:ZCollectionIntervalMajorZGC进行老年代垃圾收集(MajorGC)的时间间隔(秒)
-XX:ZYoungCompactionLimit控制ZGC何时进行年轻代的压缩操作

参考资料:

  1. 深入理解Java虚拟机第三版
  2. JEP 439: Generational ZGC
  3. JEP 377: ZGC: A Scalable Low-Latency Garbage Collector (Production)
  4. 理解并应用JVM垃圾收集器-ZGC
  5. 分代ZGC
  6. G1 垃圾收集器详解
  7. JDK17+ZGC初体验|得物技术

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

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

相关文章

Vue的MVVM实现原理

目录 前言 用法 代码和效果图 效果图 理解 高质量的使用 前言 MVVM是Model-View-ViewModel的缩写,是一种软件架构设计模式。Vue.js实现了这种设计模式,通过双向数据绑定和虚拟DOM技术,使得数据和视图能够快速响应彼此的变化。了解Vue的…

标准库STM32F1_USART2_DMA接收发送数据源码分享直接复制能用

标准库STM32F1_USART2_DMA接收发送数据源码分享直接复制能用 STM32的DMA通道表: 现有一个小需求,使用STM32F1系列单片机做串口2的收发数据的功能,通过PC上的串口调试助手给单片机发一串数据,单片机收到数据后再给PC的串口调试助手…

selenium安装和python中基本使用

selenium安装和python中基本使用 背景下载和安装浏览器驱动115.xx版本之前驱动下载115.xx及之后的高版本驱动 配置浏览器驱动安装selenium使用selenium点击按钮搜索内容 背景 selenium 出现的初衷就是一个自动化测试工具,她可以打开浏览器,然后像用户一…

软件测试进阶篇----自动化测试脚本开发

自动化测试脚本开发 一、自动化测试用例开发 1、用例设计需要注意的点 2、设计一条测试用例 二、脚本开发过程中的技术 1、线性脚本开发 2、模块化脚本开发(封装线性代码到方法或者类中。在需要的地方进行调用) 3、关键字驱动开发:selen…

php 数组基础/练习

数组 练习在最后 数组概述 概述与定义 数组中存储键值对 数组实际上是一个有序映射 key-value,可将其当成真正的数组、列表(向量)、散列表、字典、集合、栈、队列等 数组中的元素可以是任意类型的数据对象(可以嵌套数组&#…

AI作画使用指南

AI作画API使用文档请前往:https://blog.csdn.net/qq_48896417/article/details/132520804 一、定义 AI作画使用指南 二、形式 「公式」 图片主体,细节词,修饰词 细节词可以任意组合,修饰词可以限定一种风格,也可以…

永恒之蓝 ms17-010

文章目录 永恒之蓝 ms17-0101. 漏洞介绍1.1 影响版本1.2 漏洞原理 2. 信息收集2.1 主机扫描2.2 端口扫描 3. 漏洞探测4. 漏洞利用5. 特殊情况5.1 安装wine32环境5.2 安装攻击32位操作系统所用的的脚本 永恒之蓝 ms17-010 很久之前做过的永恒之蓝漏洞… 1. 漏洞介绍 永恒之蓝…

【STM32】RCC时钟模块(使用HAL库)

https://gitee.com/linhir-linhir/stm32-f103-c8/blob/master/STM32%E6%9C%80%E6%96%B0%E5%9B%BA%E4%BB%B6%E5%BA%93v3.5/Libraries/STM32F10x_StdPeriph_Driver/inc/stm32f10x_rcc.h STM32最新固件库v3.5/Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x/system_stm32f10x.c…

Linux环境开发工具yum、makefile的使用 【Linux】

文章目录 Linux软件包管理器 - yumLinux下安装软件的方式yum查找软件包如何实现本地机器和云服务器之间的文件互传卸载软件Linux编译器 - gcc/g 程序的翻译过程1.预编译(预处理)2.编译(生成汇编)3.汇编(生成机器可识别…

MySQL数据库 #3

文章目录 一、创建表的完整语法二、约束条件1.unsigned (无符号)2. zerofill (0填充)3. default (默认值)4. not null(非空)5. unique(唯一)6. primary key &…

1024程序员节背后的秘密:1024程序员节的前世今生

🌷🍁 博主猫头虎 带您 Go to New World.✨🍁 🦄 博客首页——猫头虎的博客🎐 🐳《面试题大全专栏》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 &a…

中国艺术孙溟㠭篆刻《绕绕》

孙溟展先生现在的这方篆刻作品,没有使用大篆和小篆文字来篆刻,彰显篆刻的金石魅力。一改以往的不同,以圆形组合设计,用篆刻的刀法刻出,即体现篆刻的美,又达到了作者想表达的感情。这方篆刻作品溟展先生起名…

SD NAND

文章目录 前言SD NAND vs SD 卡SD NAND vs SPI NANDCS SD NAND 优势芯片介绍结构框图引脚介绍参考设计 焊接测速单片机读写测试作为 ARM Linux 系统盘使用 前言 提到 SD,最先想到的就是 SD 卡,由于体积关系,TF 卡使用得更为普遍,…

[Ubuntu 18.04] 搭建文件夹共享之Samba服务器

Samba是一个开源项目,允许Windows用户在Linux和Unix系统上进行文件共享。 Samba服务器是一个可以让Linux或Unix系统在网络上充当Windows NT/2000/XP/2003等网络操作系统的共享资源的软件。它允许用户通过SMB/CIFS协议在Linux或Unix系统与Windows共享资源。 Samba服务器的主要…

VRPTW(MATLAB):淘金优化算法GRO求解带时间窗的车辆路径问题VRPTW(提供参考文献及MATLAB代码)

一、VRPTW简介 带时间窗的车辆路径问题(Vehicle Routing Problem with Time Windows, VRPTW)是车辆路径问题(VRP)的一种拓展类型。VRPTW一般指具有容量约束的车辆在客户指定的时间内提供配送或取货服务,在物流领域应用广泛,具有重要的实际意义。VRPTW常…

ARM | 传感器必要总线IIC

IIC总线介绍 1.谈谈你对IIC总线理解? 1)IIC总线是串行半双工同步总线,主要用于连接整体电路 2)SCL/SDA作用:IIC是两线制,一根是时钟线SCK,用于控制什么时候进行进行数据传输,时钟信号由主机发出; 另一根是数据线SDA,用于进行数据传输,可以从…

垃圾收集器与内存分配策略

概述 垃圾收集需要完成的三件事情: 哪些内存需要回收?什么时候回收?如何回收? 判断对象是都存活的算法: 引用计数法:在对象中添加一个引用计数器,每当有一个地方引用时,计数器值就…

python基础教程:异常处理

嗨喽~大家好呀,这里是魔王呐 ❤ ~! python更多源码/资料/解答/教程等 点击此处跳转文末名片免费获取 有时候我们在写程序的时候会出现错误或者异常,导致程序终止,如下这个例子: #!/usr/bin/env python a 2/0 print(a)结果提示如…

Visual Studio Professional 2019 软件安装教程(附安装包下载)

Microsoft Visual Studio 是一个非常强大的集成开发环境(IDE),适用于 Windows 上的 .NET 和 C 开发人员。它提供了一系列丰富的工具和功能,可以提升和增强软件开发的每个阶段。 Visual Studio IDE 是一个创意启动板,可…

C++ 多线程编程和同步机制:详解和实例演示

C中的多线程编程和同步机制使得程序员可以利用计算机的多核心来提高程序的运行效率和性能。本文将介绍多线程编程和同步机制的基本概念和使用方法。 多线程编程基础 在C中&#xff0c;使用<thread>库来创建和管理线程。线程可以通过函数、成员函数或者Lambda表达式来实现…