JVM垃圾回收器之ZGC收集器

ZGC,全称Z Garbage Collector。ZGC和Shenandoah的目标是高度相似的,都希望在尽可能对吞吐量影响不太大的前提下,实现在任意堆内存大小下都可以把垃圾收集的停顿时间限制在十毫秒以内的低延迟。

主要特征:ZGC收集器是一款基于Region(也有称为Page或者ZPage的)内存布局的,(暂时)不设分代的,使用了读屏障染色指针内存多重映射等技术来实现可并发的标记-整理算法的,以低延迟为首要目标的一款垃圾收集器

首先在x64硬件平台下,ZGC的 Region可以具有大、中、小三类容量:

小型Region(Small Region):容量固定为2MB,用于放置小于256KB的小对象。

中型Region(Medium Region):容量固定为32MB,用于放置大于等于256KB但小于4MB的对 象。

大型Region(Large Region):容量不固定,可以动态变化,但必须为2MB的整数倍,用于放置 4MB或以上的大对象。每个大型Region中只会存放一个大对象,这也预示着虽然名字叫作“大型 Region”,但它的实际容量完全有可能小于中型Region,最小容量可低至4MB。大型Region在ZGC的实 现中是不会被重分配(重分配是ZGC的一种处理动作,用于复制对象的收集器阶段,稍后会介绍到) 的,因为复制一个大对象的代价非常高昂。

并发整理算法的实现

染色指针技术

ZGC收集器有一个标志性的设计是它采用的染色指针技术(Colored Pointer,其他类似的技术中可 能将它称为Tag Pointer或者Version Pointer)。ZGC的染色指针是最直接的、最纯粹的,它直接把标记信息记在引用对象的指针上,这时,与其说可达性分析是遍历对象图来标记对象,还不如说是遍历“引用图”来标记“引用”了。

染色指针是一种直接将少量额外的信息存储在指针上的技术。Linux下64位指针的高18位不能用来寻址,但剩余的46位指针所能支持的64TB内存在今天仍然能够充分满足大型服务器的需要。鉴于此,ZGC的染色指针技术继续盯上了这剩下的46位指针宽 度,将其高4位提取出来存储四个标志信息。通过这些标志位,虚拟机可以直接从指针中看到其引用对象的三色标记状态是否进入了重分配集(即被移动过)、是否只能通过finalize()方法才能被访问到。当然,由于这些标志位进一步压缩了原本就只有46位的地址空间,也直接导致 ZGC能够管理的内存不可以超过4TB(2的42次幂)

染色指针的三大优势:

1、染色指针可以使得一旦某个Region的存活对象被移走之后,这个Region立即就能够被释放和重用 掉,而不必等待整个堆中所有指向该Region的引用都被修正后才能清理。

2、染色指针可以大幅减少在垃圾收集过程中内存屏障的使用数量

3、染色指针可以作为一种可扩展的存储结构用来记录更多与对象标记、重定位过程相关的数据,以 便日后进一步提高性能

现在Linux下的64位指针还有前18位并未使用,它们虽然不能用来寻址,却可 以通过其他手段用于信息记录。如果开发了这18位,既可以腾出已用的4个标志位,将ZGC可支持的 最大堆内存从4TB拓展到64TB,也可以利用其余位置再存储更多的标志,譬如存储一些追踪信息来让 垃圾收集器在移动对象时能将低频次使用的对象移动到不常访问的内存区域。

继续深挖

Java虚拟机作为一个普普通通的进程, 这样随意重新定义内存中某些指针的其中几位,操作系统是否支持?处理器是否支持? 

Linux/x86-64平台上的ZGC使用了多重映射(Multi-Mapping)将多个不同的虚拟内存地址映射到同一 个物理内存地址上,这是一种多对一映射,意味着ZGC在虚拟内存中看到的地址空间要比实际的堆内存容量来得更大。把染色指针中的标志位看作是地址的分段符,那只要将这些不同的地址段都映射到 同一个物理内存空间,经过多重映射转换后,就可以使用染色指针正常进行寻址了,效果如图所示(读不懂的多读几次😂)

工作流程 

并发标记(Concurrent Mark):

与G1、Shenandoah一样,并发标记是遍历对象图做可达性分析的 阶段,前后也要经过类似于G1、Shenandoah的初始标记、最终标记(尽管ZGC中的名字不叫这些)的短暂停顿,而且这些停顿阶段所做的事情在目标上也是相类似的。与G1、Shenandoah不同的是,ZGC 的标记是在指针上而不是在对象上进行的,标记阶段会更新染色指针中的Marked 0、Marked 1标志位。

并发预备重分配(Concurrent Prepare for Relocate):

这个阶段需要根据特定的查询条件统计得出 本次收集过程要清理哪些Region,将这些Region组成重分配集(Relocation Set)。重分配集与G1收集器 的回收集(Collection Set)还是有区别的,ZGC划分Region的目的并非为了像G1那样做收益优先的增
量回收。相反,ZGC每次回收都会扫描所有的Region,用范围更大的扫描成本换取省去G1中记忆集的 维护成本。因此,ZGC的重分配集只是决定了里面的存活对象会被重新复制到其他的Region中,里面 的Region会被释放,而并不能说回收行为就只是针对这个集合里面的Region进行,因为标记过程是针对 全堆的。此外,在JDK 12的ZGC中开始支持的类卸载以及弱引用的处理,也是在这个阶段中完成的。

 并发重分配(Concurrent Relocate):

重分配是ZGC执行过程中的核心阶段,这个过程要把重分配集中的存活对象复制到新的Region上,并为重分配集中的每个Region维护一个转发表(Forward Table),记录从旧对象到新对象的转向关系。得益于染色指针的支持,ZGC收集器能仅从引用上就明 确得知一个对象是否处于重分配集之中,如果用户线程此时并发访问了位于重分配集中的对象,这次 访问将会被预置的内存屏障所截获,然后立即根据Region上的转发表记录将访问转发到新复制的对象 上,并同时修正更新该引用的值,使其直接指向新对象,ZGC将这种行为称为指针的“自愈”(Self- Healing)能力。这样做的好处是只有第一次访问旧对象会陷入转发,也就是只慢一次,对比 Shenandoah的Brooks转发指针,那是每次对象访问都必须付出的固定开销,简单地说就是每次都慢, 因此ZGC对用户程序的运行时负载要比Shenandoah来得更低一些。还有另外一个直接的好处是由于染 色指针的存在,一旦重分配集中某个Region的存活对象都复制完毕后,这个Region就可以立即释放用于 新对象的分配(但是转发表还得留着不能释放掉),哪怕堆中还有很多指向这个对象的未更新指针也 没有关系,这些旧指针一旦被使用,它们都是可以自愈的。

并发重映射(Concurrent Remap):

重映射所做的就是修正整个堆中指向重分配集中旧对象的所 有引用,这一点从目标角度看是与Shenandoah并发引用更新阶段一样的,但是ZGC的并发重映射并不 是一个必须要“迫切”去完成的任务,因为前面说过,即使是旧引用,它也是可以自愈的,最多只是第 一次使用时多一次转发和修正操作。重映射清理这些旧引用的主要目的是为了不变慢(还有清理结束 后可以释放转发表这样的附带收益),所以说这并不是很“迫切”。因此,ZGC很巧妙地把并发重映射 阶段要做的工作,合并到了下一次垃圾收集循环中的并发标记阶段里去完成,反正它们都是要遍历所 有对象的,这样合并就节省了一次遍历对象图的开销。一旦所有指针都被修正之后,原来记录新旧 对象关系的转发表就可以释放掉了。

所以ZGC与Shenandoah一样做到了几乎整个收集过程都全程可并发,短暂停顿也只与GC Roots大小相关而与堆内存大小无关,因而同样实现了任何堆上停顿都小于十毫秒的目标。

与其他垃圾收集器相比 

G1

通过写屏障来维护记忆集,才能处理跨代指针,得以实现Region的增量回收。记忆集要占用大量 的内存空间,写屏障也对正常程序运行造成额外负担,这些都是权衡选择的代价

CMS

记录新生代和老年代间引用的卡表

ZGC缺点

它能承受的对象分配速率不会太高。解释:假设其全过程要持续十分钟以上,在这段时间里面,由于应用的对象分配速率很高,将创造大量的新对象,这些新对象很难进入当次收集的标记范围,通常就只能全部当作存活对象来看待——尽管其中绝大部分对象都是朝生夕灭的,这就产生了大 量的浮动垃圾。如果这种高速分配持续维持的话,每一次完整的并发收集周期都会很长,回收到的内 存空间持续小于期间并发产生的浮动垃圾所占的空间,堆中剩余可腾挪的空间就越来越小了。

若要从根本上提升ZGC能够应对 的对象分配速率,还是需要引入分代收集,让新生对象都在一个专门的区域中创建,然后专门针对这 个区域进行更频繁、更快的收集

在性能方面,尽管目前还处于实验状态,还没有完成所有特性,稳定性打磨和性能调优也仍在进 行,但即使是这种状态下的ZGC,其性能表现已经相当亮眼,从官方给出的测试结果来看,用“令 人震惊的、革命性的ZGC”来形容都不为过。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
以下是几个 JVM 垃圾回收相关的面试题及其答案: 1. JVM 垃圾回收都有哪些? JVM 垃圾回收主要分为以下几种:串行垃圾回收、并行垃圾回收、CMS 垃圾回收、G1 垃圾回收等。 2. 串行垃圾回收和并行垃圾回收的区别是什么? 串行垃圾回收和并行垃圾回收的主要区别在于垃圾回收的方式。串行垃圾回收是单线程执行的,即在垃圾回收过程中只有一个线程在执行,而并行垃圾回收是多线程执行的,即在垃圾回收过程中可以有多个线程同时执行。 3. CMS 垃圾回收的特点是什么? CMS 垃圾回收是一种以最短回收停顿时间为目标的垃圾回收。它采用分代收集算法,在回收老年代时,采用标记-清除算法,并发标记和并发清除,以减少垃圾回收的停顿时间,提高系统的响应速度。 4. G1 垃圾回收的特点是什么? G1 垃圾回收是一种面向服务端应用的垃圾回收,它采用分代收集算法,在回收堆内存时,采用标记-整理算法。它具有以下特点:高效、可预测、可配置、可并发、可暂停等。 5. 垃圾回收的主要算法有哪些? 垃圾回收主要采用以下几种算法:标记-清除算法、复制算法、标记-整理算法、分代算法等。 以上是一些常见的 JVM 垃圾回收面试题及其答案,希望能对你有所帮助。在面试过程中,需要根据具体的问题进行回答,同时也需要对垃圾回收的原理和实现有清晰的认识,才能更好地回答相关的问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值