深入理解JVM《ZGC:超低延迟的可扩展垃圾收集器》

简介: ZGC是JDK 11引入、15正式发布的低延迟垃圾收集器,目标是堆大小无关的10ms内停顿。其核心通过“着色指针”和“读屏障”实现标记与重定位的并发执行,极大减少STW时间,适用于大内存、高实时场景,虽有CPU开销但吞吐影响小,调优简单,是未来Java GC的发展方向。

ZGC(Z Garbage Collector)是Oracle在JDK 11中引入的一款实验性的低延迟垃圾收集器,并在JDK 15中正式发布。它的设计目标是:在任意堆内存大小下(从几百MB到数TB),将垃圾收集的停顿时间控制在10毫秒以内。这是一个极其雄心勃勃的目标,旨在解决G1和CMS在大堆应用上仍然可能产生较长停顿的问题。

核心目标与设计理念

ZGC的核心设计理念是几乎所有的垃圾收集工作都是并发执行的,从而将STW(Stop-The-World)停顿缩短到仅有的几个毫秒级阶段。为了实现这一目标,ZGC采用了两大基石技术:着色指针读屏障

核心技术:着色指针与读屏障

1. 着色指针 (Colored Pointers)

这是ZGC的基石。它颠覆了传统观念,在指针本身而不是在对象头上存储元数据信息。

在64位平台上,一个指针的理论寻址空间是2^64字节,这是一个极其巨大的空间。而实际上,现代硬件和操作系统并不会使用完所有64位。Linux/x86_64平台通常使用48位虚拟地址空间(高16位为符号扩展),而AMD64架构支持52位物理地址空间。ZGC巧妙地利用了这些未使用的指针位来存储信息。

ZGC使用了64位指针中的4个位(称为“元位”)来标记对象的状态:

  • Finalizable:对象只能通过finalizer访问。
  • Remapped:对象已被重映射(即新的地址已被记录)。
  • Marked1:标记状态1。
  • Marked0:标记状态0。

这些“颜色”标记了对象在GC周期中的状态。通过操作指针的颜色位,ZGC可以高效地并发执行标记和重定位(压缩)操作,而无需暂停所有应用线程。

2. 读屏障 (Load Barrier)

读屏障是JVM在从堆内存加载引用时插入的一小段代码。可以把它想象成一个“陷阱”或一个“钩子”。每当应用程序线程从堆中读取一个对象引用时(例如 Object foo = obj.field;),ZGC的读屏障就会被触发。

读屏障的核心作用:根据着色指针的颜色位,“治愈” 这个引用。

  • 如果读到的指针颜色显示该对象尚未被处理(例如,尚未被标记或尚未被重定位),读屏障会主动介入,完成相应的处理工作(例如,标记对象或更新引用到新地址)。
  • 如果指针颜色显示一切正常,则读屏障几乎不做任何事,开销极低。

正是“着色指针+读屏障”的结合,使得ZGC的标记和重定位两大最耗时的任务能够与应用线程并发执行。

ZGC的执行过程

ZGC的GC周期可以分为几个阶段,其中标记重定位是核心。

1. 初始标记 (Pause Mark Start)

  • 任务:从GC Roots(线程栈、全局变量等)开始,标记所有直接可达的对象。这是一个非常快速的、STW的过程。
  • 过程:遍历GC Roots,将直接引用的对象压入标记栈中。

2. 并发标记 (Concurrent Mark)

  • 任务:从标记栈中的对象开始,递归遍历整个对象图,标记所有存活的对象。
  • 状态完全并发。应用线程仍在运行。
  • 关键技术:读屏障。当应用线程加载一个尚未被标记的对象的引用时,读屏障会拦截该引用,并完成对该对象的标记(将其颜色位设为Marked0或Marked1),并将其加入标记栈。这确保了所有在并发标记阶段被访问到的对象都会被正确标记。

3. 最终标记 (Pause Mark End)

  • 任务:处理一些边缘情况(如弱引用处理),并确保标记栈是空的,标志着整个对象图的标记工作已经完成。
  • 状态:一个非常短暂的 STW 停顿。

4. 并发准备重定位 (Concurrent Prepare for Relocate)

  • 任务:根据标记结果(存活对象),筛选出哪些内存区域包含最多的垃圾(即最适合进行压缩回收),并创建重分配集(Relocation Set)。

5. 初始重定位 (Pause Relocate Start)

  • 任务:为重分配集中的每个Region分配转发指针(Forwarding Pointer)所需的数据结构。
  • 状态:一个非常短暂的 STW 停顿。

6. 并发重定位 (Concurrent Relocate)

  • 任务:这是ZGC最核心、最神奇的部分。它将重分配集中的存活对象复制到新的Region中
  • 状态完全并发
  • 工作原理
  • GC线程开始复制存活对象到新的Region。
  • 同时,应用线程仍在运行,并可能访问已被重定位或尚未重定位的对象。
  • 读屏障再次发挥关键作用
  • 如果一个应用线程尝试访问一个尚未被重定位的对象,读屏障会先完成这个对象的复制工作,然后更新应用线程手中的引用,使其指向新地址。
  • 如果一个应用线程尝试访问一个已经被其他线程重定位的对象,读屏障会通过对象旧地址上的“转发指针”来“治愈”这个引用,直接返回新地址。
  • 这个过程确保了所有引用最终都会被正确地更新到新地址,而无需暂停应用线程。

下图展示了ZGC如何通过其并发的标记和重定位阶段,将漫长的STW时间分解为多个极短的停顿,从而实现其超低延迟的目标:

ZGC如何解决“对象消失”问题

与G1的SATB和CMS的增量更新不同,ZGC的并发标记基于一种称为 “指针着色” 的机制,它本身通过读屏障就足以保证标记的正确性。

在ZGC的并发标记阶段:

  1. 对象的状态通过指针的颜色位来标识(Marked0/Marked1)。
  2. 当应用线程试图将一个引用写入某个字段时(A.field = B),它只是简单地存储了一个指向B的指针(可能带着未标记的颜色)。
  3. 当另一个线程(或之后同一个线程)读取 A.field 时,读屏障会被触发
  4. 读屏障检查引用B的颜色。如果它尚未被标记,读屏障会立即将其标记(修改颜色位),然后再将“治愈”后的正确引用返回给应用线程。

这种方式确保了:

  • 任何被存活对象引用的对象,在引用被读取时都会被立刻标记,从而不会被错误回收。
  • 它不需要像G1那样维护复杂的RSet来跟踪跨Region引用,因为“治愈”工作是在读取时即时完成的。

ZGC的优缺点与调优

优点

  1. 超低停顿:停顿时间通常不超过10ms,且不随堆大小增长而增长。
  2. 高吞吐量:虽然引入了读屏障,但其设计非常高效,吞吐量损失相对于G1通常只在15%以内。
  3. 简化的调优:参数远比G1简单,核心目标通常只需设定最大停顿时间(-XX:MaxGCPauseMillis)。

缺点与注意事项

  1. CPU开销:读屏障虽然高效,但仍会带来额外的CPU开销。在CPU极度紧张的应用中,可能需要评估其影响。
  2. JDK版本:生产环境强烈建议使用其正式版后的LTS版本,如JDK 17或JDK 21,以获得最佳的稳定性和性能。
  3. 观察性工具:传统的jstat等工具对ZGC的支持有限,需要依赖ZGC自己的日志和更新的工具(如JDK的jcmd、GC日志分析)来进行监控和调优。

关键参数

  • 启用ZGC-XX:+UseZGC
  • 设置最大停顿时间目标-XX:MaxGCPauseMillis=5 (单位ms,默认无目标,但ZGC会尽力优化)
  • 启用并行GC线程动态调整-XX:+UseDynamicGCThreads (推荐,默认开启)
  • 开启GC日志-Xlog:gc*:gc.log (JDK 9+ Unified Logging格式)

总结

ZGC代表了Java垃圾收集技术的前沿。它通过革命性的着色指针读屏障技术,将GC停顿时间降低到了一个前所未有的水平,几乎让Java应用程序感觉不到垃圾收集的存在。尽管它需要更高的JDK版本支持,并且可能带来轻微的CPU开销,但对于追求极致响应速度的应用(如金融交易、大数据处理、实时游戏服务器),ZGC是一个改变游戏规则的选择。随着JDK的持续演进,ZGC正变得越来越成熟和稳定,是未来Java大内存低延迟应用的默认选择。

相关文章
|
15天前
|
存储 关系型数据库 分布式数据库
PostgreSQL 18 发布,快来 PolarDB 尝鲜!
PostgreSQL 18 发布,PolarDB for PostgreSQL 全面兼容。新版本支持异步I/O、UUIDv7、虚拟生成列、逻辑复制增强及OAuth认证,显著提升性能与安全。PolarDB-PG 18 支持存算分离架构,融合海量弹性存储与极致计算性能,搭配丰富插件生态,为企业提供高效、稳定、灵活的云数据库解决方案,助力企业数字化转型如虎添翼!
|
10天前
|
缓存 并行计算 PyTorch
144_推理时延优化:Profiling与瓶颈分析 - 使用PyTorch Profiler诊断推理延迟,优化矩阵运算的独特瓶颈
在2025年的大模型时代,推理时延优化已经成为部署LLM服务的关键挑战之一。随着模型规模的不断扩大(从数亿参数到数千亿甚至万亿参数),即使在最先进的硬件上,推理延迟也常常成为用户体验和系统吞吐量的主要瓶颈。
349 147
|
10天前
|
机器学习/深度学习 存储 缓存
92_自我反思提示:输出迭代优化
在大型语言模型(LLM)应用日益普及的今天,如何持续提升模型输出质量成为了业界关注的核心问题。传统的提示工程方法往往依赖一次性输入输出,难以应对复杂任务中的多轮优化需求。2025年,自我反思提示技术(Self-Reflection Prompting)作为提示工程的前沿方向,正在改变我们与LLM交互的方式。这项技术通过模拟人类的自我反思认知过程,让模型能够对自身输出进行评估、反馈和优化,从而实现输出质量的持续提升。
400 136
|
4天前
|
人工智能 移动开发 自然语言处理
阿里云百炼产品月刊【2025年9月】
本月通义千问模型大升级,新增多模态、语音、视频生成等高性能模型,支持图文理解、端到端视频生成。官网改版上线全新体验中心,推出高代码应用与智能体多模态知识融合,RAG能力增强,助力企业高效部署AI应用。
255 1
|
14天前
|
存储 人工智能 搜索推荐
终身学习型智能体
当前人工智能前沿研究的一个重要方向:构建能够自主学习、调用工具、积累经验的小型智能体(Agent)。 我们可以称这种系统为“终身学习型智能体”或“自适应认知代理”。它的设计理念就是: 不靠庞大的内置知识取胜,而是依靠高效的推理能力 + 动态获取知识的能力 + 经验积累机制。
405 135
|
14天前
|
存储 人工智能 Java
AI 超级智能体全栈项目阶段二:Prompt 优化技巧与学术分析 AI 应用开发实现上下文联系多轮对话
本文讲解 Prompt 基本概念与 10 个优化技巧,结合学术分析 AI 应用的需求分析、设计方案,介绍 Spring AI 中 ChatClient 及 Advisors 的使用。
531 133
AI 超级智能体全栈项目阶段二:Prompt 优化技巧与学术分析 AI 应用开发实现上下文联系多轮对话
|
14天前
|
人工智能 Java API
AI 超级智能体全栈项目阶段一:AI大模型概述、选型、项目初始化以及基于阿里云灵积模型 Qwen-Plus实现模型接入四种方式(SDK/HTTP/SpringAI/langchain4j)
本文介绍AI大模型的核心概念、分类及开发者学习路径,重点讲解如何选择与接入大模型。项目基于Spring Boot,使用阿里云灵积模型(Qwen-Plus),对比SDK、HTTP、Spring AI和LangChain4j四种接入方式,助力开发者高效构建AI应用。
545 122
AI 超级智能体全栈项目阶段一:AI大模型概述、选型、项目初始化以及基于阿里云灵积模型 Qwen-Plus实现模型接入四种方式(SDK/HTTP/SpringAI/langchain4j)