细说jvm(八)、垃圾回收器ZGC

简介: 细说jvm(八)、垃圾回收器ZGC

一、简介


ZGC这个名字中的Z,并不是什么单词的缩写,这个垃圾回收器的英文名字就叫做Z Garbage Collector,是一款追求低延迟的垃圾回收器,在jdk11中被加入到垃圾回收器家族中,注意在这个版本中,它是具有实验性质的,如果想在生产中使用,建议使用更高版本的jdk。


二、工作原理

与CMS中的ParNew和G1类似,ZGC也采用标记-复制算法,不过ZGC对该算法做了重大改进:ZGC在标记、转移和重定位阶段几乎都是并发的,这是ZGC停顿时间及其短的关键所在。

ZGC垃圾回收周期如下图所示:


1686815427274.png


  • 并发标记(Concurrent Mark):与G1一样,并发标记是遍历对象图做可达性分析的阶段,前后也要经过类似于G1初始标记和最终标记(ZGC中就是名字不同而已)的短暂的停顿,整个标记阶段只会更新染色指针中的Marked 0、Marked 1标志位。停顿时间和堆大小无关,只和GC Roots数量有关。总结就是:并发标记阶段会有两个短暂STW。ZGC只有短暂的STW,大部分的过程都是和应用线程并发执行,比如最耗时的并发标记和并发移动过程。
  • 并发预备重分配(Concurrent Prepare for Relocate):这个阶段需要根据特定的查询条件统计得出本次收集过程要清理哪些Region,将这些Region组成重分配集(Relocation Set)。ZGC每次回收都会扫描所有的Region,用范围更大的扫描成本换取省去G1中记忆集的维护成本。ZGC的重分配集只是决定里面的存活对象会被复制到其他的Region。不是为了效益回收。JDK12的ZGC中开始支持的类卸载以及弱引用的处理,也是在这个阶段完成的。
  • 并发重分配(Concurrent Relocate):重分配是ZGC执行过程中的核心阶段,这个过程要把重分配集中的存活对象复制到新的Region上,并为重分配集中的每个Region维护一个转发表(Forward Table),记录从旧对象到新对象的转向关系。ZGC收集器能仅从引用上就明确得知一个对象是否处于重分配集之中,如果用户线程此时并发访问了位于重分配集中的对象,这次访问将会被预置的内存屏障所截获,然后立即根据Region上的转发表记录将访问转发到新复制的对象上,并同时修正更新该引用的值,使其直接指向新对象,ZGC将这种行为称为指针的“自愈”(Self-Healing)能力。ZGC的染色指针因为“自愈”(Self-Healing)能力,所以只有第一次访问旧对象会变慢,而Shenandoah的Brooks转发指针是每次都会变慢。 一旦重分配集中某个Region的存活对象都复制完毕后,这个Region就可以立即释放用于新对象的分配,但是转发表还得留着不能释放掉,因为可能还有访问在使用这个转发表。 举例如:因为在标记和移动过程中,GC线程和应用线程是并发执行的,所以存在这种情况:对象A内部的引用所指的对象B在标记或者移动状态,为了保证应用线程拿到的B对象是对的,那么在读取B的指针时会经过一个 “load barriers” 读屏障,这个屏障可以保证在执行GC时,数据读取的正确性。
  • 并发重映射(Concurrent Remap):重映射所做的就是修正整个堆中指向重分配集中旧对象的所有引用,但是ZGC中对象引用存在“自愈”功能,所以这个重映射操作并不是很迫切。ZGC很巧妙地把并发重映射阶段要做的工作,合并到了下一次垃圾收集循环中的并发标记阶段里去完成,反正它们都是要遍历所有对象的,这样合并就节省了一次遍历对象图的开销。

总结一下,STW的时间段是初始标记,再标记,初始转移(就是被我用很丑的字体标出来的那块)。初始标记和初始转移分别都只需要扫描所有GC Roots,其处理时间和GC Roots的数量成正比,一般情况耗时非常短;再标记阶段STW时间很短,最多1ms,超过1ms则再次进入并发标记阶段。即,ZGC几乎所有暂停都只依赖于GC Roots集合大小,停顿时间不会随着堆的大小或者活跃对象的大小而增加。与ZGC对比,G1的转移阶段完全STW的,且停顿时间随存活对象的大小增加而增加。


三、关键技术


1、染色指针和lvb

这两个技术是位了解决并发转移过程中准确访问对象的问题。


为了防止你看懵,我解释下并发过程转移过程中对象访问问题
并发转移中“并发”意味着GC线程在转移对象的过程中,应用线程也在不停地访问对象。假设对象发生转移,但对象地址未及时更新,
那么应用线程可能访问到旧地址,从而造成错误


染色指针是一种将信息存储在指针中的技术,而ZGC中的染色指针指的是把对象的状态存储在指针中,ZGC把64位虚拟地址空间划分为多个子空间(这是它仅支持6位系统的原因),如下图所示:



1686815418056.png


标记信息存储在引用对象的指针上:高18位没有使用,4位用来存储标记信息,低42位存储对象地址,最重要的是用来存储标记信息的这4位,作用分别如下:

  • Marked0 /Marked1:标记位,标记对象是否可用,
  • Remapped:记录对象是否进入过重分配集(对象是否移动过)
  • Finalizable:标记对象是否只能通过fnalize()访问 使用两个标记位Marked0、Marked1:在不同的回收周期交替使用,上一回收周期的标志位在本周期失效,重置为0,如:一个周期中使用Marked0,存活对象标记为01,则下一个周期使用标记位Marked1,存活对象标记为10。

lvb的本质上是读屏障,读屏障你可以理解为读对象之前的aop,也就是读对象之前做了一些别的事情。引用R大的话说,在ZGC中,LVB做的事情都有:在标记阶段它会把指针标记上并把堆里的这个指针给“修正”到新的标记后的值;而在移动对象的阶段,这个屏障会把读出的指针更新到对象的新地址上,并且把堆里的这个指针“修正”到原本的字段里。这样就算GC把对象移动了,读屏障也会发现并修正指针,于是应用代码就永远都会持有更新后的有效指针,而不需要通过stop-the-world这种最粗粒度的同步方式来让GC与应用之间同步,其实这也就是所谓的自愈(self-healing)。


2、支持NUMA—Aware

NUMA(Non-Uniform Memory Access,非统一内存访问架构)是一种多处理器或多核处理器计算机所设计的内存架构。

现在多CPU插槽的服务器都是Numa架构,比如两颗CPU插槽(24核),64G内存的服务器,那其中一颗CPU上的12个核,访问从属于它的32G本地内存,要比访问另外32G远端内存要快得多。 ZGC默认支持NUMA架构,在创建对象时,根据当前线程在哪个CPU执行,优先在靠近这个CPU的内存进行分配,这样可以显著的提高性能。


四、再聊分区和分代


1、ZGC中的分区技术

ZGC也使用了分区,和G1不同的是ZGC中根据不同大小,将区分成了如下几种(其实ZGC的术语中这个叫Page):

  • 小型region:固定为2M,用于存储小于256KB的小对象;
  • 中型region:固定为32M,用于存储大于等于256KB,小于4M的对象;
  • 大型region:大小可变化,需为2M的整数倍,存储大于等于4M的对象,大型region最小为4M,每个大region中只会存放一个大对象。大型region是不会进行重分配的动作的,因为复制大对象的代价还是很大的。

2、分代技术和分区技术

分区和分代的细节我就不介绍了,不明白的可以看看前面的文章。分区和分代是丝毫不冲突的,这也是很多人不理解的地方,其实这完全是两件不同的事情,但是目的是相同的,都是避免一次性扫描太大的内存空间而造成延迟增加和吞吐量的降低。那为什么ZGC没有分代呢,通过查看各种资料发现,其实ZGC也在规划分代,所以之前没有应该也纯粹就是因为设计者的时间问题吧。

五、常见参数

目录
相关文章
|
4月前
|
存储 算法 Oracle
极致八股文之JVM垃圾回收器G1&ZGC详解
本文作者分享了一些垃圾回收器的执行过程,希望给大家参考。
|
1月前
|
监控 算法 Java
Java虚拟机(JVM)的垃圾回收机制深度解析####
本文深入探讨了Java虚拟机(JVM)的垃圾回收机制,旨在揭示其背后的工作原理与优化策略。我们将从垃圾回收的基本概念入手,逐步剖析标记-清除、复制算法、标记-整理等主流垃圾回收算法的原理与实现细节。通过对比不同算法的优缺点及适用场景,为开发者提供优化Java应用性能与内存管理的实践指南。 ####
|
23天前
|
监控 算法 Java
Java虚拟机(JVM)垃圾回收机制深度剖析与优化策略####
本文作为一篇技术性文章,深入探讨了Java虚拟机(JVM)中垃圾回收的工作原理,详细分析了标记-清除、复制算法、标记-压缩及分代收集等主流垃圾回收算法的特点和适用场景。通过实际案例,展示了不同GC(Garbage Collector)算法在应用中的表现差异,并针对大型应用提出了一系列优化策略,包括选择合适的GC算法、调整堆内存大小、并行与并发GC调优等,旨在帮助开发者更好地理解和优化Java应用的性能。 ####
30 0
|
16小时前
|
算法 网络协议 Java
【JVM】——GC垃圾回收机制(图解通俗易懂)
GC垃圾回收,标识出垃圾(计数机制、可达性分析)内存释放机制(标记清除、复制算法、标记整理、分代回收)
|
23天前
|
存储 监控 算法
Java虚拟机(JVM)垃圾回收机制深度解析与优化策略####
本文旨在深入探讨Java虚拟机(JVM)的垃圾回收机制,揭示其工作原理、常见算法及参数调优方法。通过剖析垃圾回收的生命周期、内存区域划分以及GC日志分析,为开发者提供一套实用的JVM垃圾回收优化指南,助力提升Java应用的性能与稳定性。 ####
|
27天前
|
机器学习/深度学习 监控 算法
Java虚拟机(JVM)的垃圾回收机制深度剖析####
本文深入探讨Java虚拟机(JVM)的垃圾回收机制,揭示其工作原理、常见算法、性能调优策略及未来趋势。通过实例解析,为开发者提供优化Java应用性能的思路与方法。 ####
39 1
|
1月前
|
监控 算法 Java
Java虚拟机垃圾回收机制深度剖析与优化策略####
【10月更文挑战第21天】 本文旨在深入探讨Java虚拟机(JVM)中的垃圾回收机制,揭示其工作原理、常见算法及参数调优技巧。通过案例分析,展示如何根据应用特性调整GC策略,以提升Java应用的性能和稳定性,为开发者提供实战中的优化指南。 ####
41 5
|
1月前
|
存储 算法 安全
JVM常见面试题(四):垃圾回收
堆区域划分,对象什么时候可以被垃圾器回收,如何定位垃圾——引用计数法、可达性分析算法,JVM垃圾回收算法——标记清除算法、标记整理算法、复制算法、分代回收算法;JVM垃圾回收器——串行、并行、CMS垃圾回收器、G1垃圾回收器;强引用、软引用、弱引用、虚引用
|
29天前
|
存储 算法 Java
JVM进阶调优系列(10)敢向stop the world喊卡的G1垃圾回收器 | 有必要讲透
本文详细介绍了G1垃圾回收器的背景、核心原理及其回收过程。G1,即Garbage First,旨在通过将堆内存划分为多个Region来实现低延时的垃圾回收,每个Region可以根据其垃圾回收的价值被优先回收。文章还探讨了G1的Young GC、Mixed GC以及Full GC的具体流程,并列出了G1回收器的核心参数配置,帮助读者更好地理解和优化G1的使用。
|
1月前
|
监控 Java 测试技术
Elasticsearch集群JVM调优垃圾回收器的选择
Elasticsearch集群JVM调优垃圾回收器的选择
54 1