深入理解ZGC回收器---背景概念&回收流程
⭐⭐⭐⭐⭐⭐
Github主页👉https://github.com/A-BigTree
笔记链接👉https://github.com/A-BigTree/Code_Learning
⭐⭐⭐⭐⭐⭐
如果可以,麻烦各位看官顺手点个star~😊
文章目录
- 深入理解ZGC回收器---背景概念&回收流程
-
- [1 ZGC诞生的背景](#1 ZGC诞生的背景)
-
- [1.1 GC之痛](#1.1 GC之痛)
- [1.2 CMS与G1瓶颈](#1.2 CMS与G1瓶颈)
- [2 ZGC特点](#2 ZGC特点)
-
- 2.1目标
- [2.2 性能表现](#2.2 性能表现)
- [3 ZGC流程简介](#3 ZGC流程简介)
关于JVM回收器的前置知识点:
- 【JVM】---Java内存区域详解
- 【JVM】---JVM垃圾回收详解
- 【JVM】---深入理解G1回收器------概念详解
- 【JVM】---深入理解G1回收器---回收过程详解
- 【JVM】---G1中的Young GC、Mixed GC、Full GC详解
- 【JVM】---G1 GC日志详解
ZGC(The Z Garbage Collector) 是JDK 11中推出的一款低延迟垃圾回收器,它的设计目标包括:
- 停顿时间不超过10ms;
- 停顿时间不会随着堆的大小,或者活跃对象的大小而增加;
- 支持8MB~4TB级别的堆(未来支持16TB)。
1 ZGC诞生的背景
1.1 GC之痛
STW(Stop-The-World)问题是垃圾回收过程中所有应用线程被强制暂停等待垃圾回收完成的现象,这会导致应用程序响应延迟,影响用户体验和系统性能,特别是在处理大量数据或高并发请求的场景下,STW问题更为突出,成为优化高性能应用的关键挑战。例如,在在线游戏服务器、金融交易系统或实时数据分析平台中,STW现象可能导致玩家体验卡顿、交易延迟或数据处理中断,严重影响系统稳定性和用户满意度。这些场景对延迟极其敏感,STW问题的出现会直接损害业务运行效率。为解决这个问题,一款跨时代的垃圾回收器ZGC诞生。
1.2 CMS与G1瓶颈
在介绍ZGC之前,首先回顾一下CMS和G1的GC过程以及停顿时间的瓶颈。CMS新生代的Young GC、G1和ZGC都基于标记-复制算法,但算法具体实现的不同就导致了巨大的性能差异。
标记-复制算法应用在CMS新生代(ParNew是CMS默认的新生代垃圾回收器)和G1垃圾回收器中。标记-复制算法可以分为三个阶段:
- 标记阶段,即从GC Roots集合开始,标记活跃对象;
- 转移阶段,即把活跃对象复制到新的内存地址上;
- 重定位阶段,因为转移导致对象的地址发生了变化,在重定位阶段,所有指向对象旧地址的指针都要调整到对象新的地址上。
下面以G1为例,通过G1中标记-复制算法过程(G1的Young GC和Mixed GC均采用该算法),分析G1停顿耗时的主要瓶颈。G1垃圾回收周期如下图所示:
G1的混合回收过程可以分为标记阶段、清理阶段和复制阶段。
标记阶段停顿分析
- 初始标记阶段:初始标记阶段是指从GC Roots出发标记全部直接子节点的过程,该阶段是STW的。由于GC Roots数量不多,通常该阶段耗时非常短;
- 并发标记阶段:并发标记阶段是指从GC Roots开始对堆中对象进行可达性分析,找出存活对象。该阶段是并发的,即应用线程和GC线程可以同时活动。并发标记耗时相对长很多,但因为不是STW,所以我们不太关心该阶段耗时的长短;
- 再标记阶段:重新标记那些在并发标记阶段发生变化的对象。该阶段是STW的。
清理阶段停顿分析
- 清理阶段清点出有存活对象的分区和没有存活对象的分区,该阶段不会清理垃圾对象,也不会执行存活对象的复制。该阶段是STW的。
复制阶段停顿分析
- 复制算法中的转移阶段需要分配新内存和复制对象的成员变量。转移阶段是STW的,其中内存分配通常耗时非常短,但对象成员变量的复制耗时有可能较长,这是因为复制耗时与存活对象数量与对象复杂度成正比。对象越复杂,复制耗时越长。
四个STW过程中,初始标记因为只标记GC Roots,耗时较短。再标记因为对象数少,耗时也较短。清理阶段因为内存分区数量少,耗时也较短。转移阶段要处理所有存活的对象,耗时会较长。因此,G1停顿时间的瓶颈主要是标记-复制中的 转移阶段 STW。
为什么转移阶段不能和标记阶段一样并发执行呢?
主要是G1未能解决转移过程中准确定位对象地址的问题。
G1的Young GC和CMS的Young GC,其标记-复制全过程STW,这里不再详细阐述。
2 ZGC特点
2.1目标
- 低延迟保证:ZGC旨在将垃圾回收引起的暂停时间控制在毫秒级别 ,即使在处理TB级堆内存的情况下,也能保持极低的停顿时间,非常适合对延迟敏感的应用。
- 并行与并发处理:ZGC充分利用多核处理器的能力,实现并行的垃圾回收操作,并且在部分阶段能够与应用线程并发执行,极大减少了STW事件的发生,提高了系统的整体响应速度。
- 可扩展性: ZGC针对现代数据中心的大内存环境进行了优化,支持从几GB到数TB的堆大小,适应了从小型服务器到大规模集群的广泛部署场景。
- 无碎片内存管理: 通过实现无碎片的内存分配和回收机制,ZGC避免了内存碎片化问题,简化了内存管理,从而提升了内存使用效率和应用性能。
- 自适应调整:ZGC具备智能的 自适应能力,能够根据系统当前的负载情况动态调整垃圾回收策略,确保在不同工作负载下都能维持良好的性能表现。
- 详尽的性能监控: 提供了丰富的垃圾回收日志和监控工具,帮助开发者深入理解ZGC的行为,进行性能调优,确保应用在各种条件下都能达到最优状态。
2.2 性能表现
- 从最大吞吐量与关键吞吐量指标观察,可以看出ZGC在关键吞吐量表现很突出
- 从停顿时间指标来观察,停顿时间是 断崖式领先
3 ZGC流程简介
-
初始标记阶段:
ZGC初始化时会为堆分配内存,并将所有对象标记为"存活"状态。
-
并发标记阶段:
这个阶段主要识别哪些对象是不再使用的。ZGC使用了基于Card Table的追踪算法(G1中的CSet与RSet概念)来发现引用关系。标记过程是并发的,意味着它可以与应用程序的执行同时进行,以减少停顿时间。在这个过程中,ZGC会维护一个引用队列,用于跟踪新创建的对象或更新的引用。
-
再标记阶段:
虽然ZGC的目标是最小化暂停时间,但仍然需要短暂的暂停来安全地重定位对象。
在这个短暂的暂停期间,ZGC会更新根集(如线程栈、JNI全局引用等)和其他需要更新的地方,确保所有引用指向正确的位置。对象被移动到新的位置,以优化内存布局和减少碎片。
-
并发转移准备阶段:
这个阶段是在上一步暂停之后开始的,它是并发执行 的,准备重定位对象。ZGC会计算每个区域中的对象需要移动的距离,以及更新引用所需的更改。
-
初始转移阶段:
在此阶段,ZGC实际移动对象并更新引用。
-
并发转移阶段:
清理阶段 处理一些剩余的任务,如释放不再需要的内存块,更新元数据等。这个阶段也是并发的,对应用程序的影响最小。
但是,在一次GC之后,并 不会真正的执行完流程 ,它是需要两次GC才能完整的执行完一次垃圾回收,这就涉及到了后面要提到的指针着色技术,使用这样的技术极大的提升了效率。
ZGC关键技术详细介绍👉【JVM】---深入理解ZGC回收器---关键技术详解