持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第 13 天,点击查看活动详情
1 前言
在前文中已经分享了 G1 垃圾回收器的内容,在本文中将继续分析低延迟垃圾回收器,衡量低延迟垃圾回收器有三个重要的指标:内存占用(Footprint)、吞吐量(Throughput)、以及低延迟(Latency)。目前比较优秀的垃圾回收器代表有两款:Shennandoah 和 ZGC,在本文中将分享 ZGC 的内容。
2 ZGC 垃圾回收器
ZGC 是以吞吐量优先,并且降低停顿时间为目标的垃圾回收器。ZGC 也采用基于 Region 的堆内存布局,但是 ZGC 将 Region 分为大中小三种容量类型:
- 1 Small Region 即小型 Region, 容量固定为 2MB,用于存放小于 256KB 的对象。
- 2 Medium Region 即中型 Region, 容量固定为 32MB,用于存放大于 256KB 且小于 4MB 的对象。
- 3 Large Region 即大型 Region, 容量不固定,为 2MB 的整数倍,用于存放 4MB 以上大小的对象。
ZGC 的并发整理算法实现是依靠染色指针技术和读屏障来实现的,我们都知道在操作系统中,指针的大小一般都是 4 字节 32 为, 在 64 位的操作系统中,指针的大小是 8 字节 64 位,这样理论上最大访问的内存高达 16EB。但是在实际操作中,对象寻址只用了 42 位,高四位用来作为标识(Finalizable 即对象是否销毁标识,remapped 是否进入重分配集, marked0 和 marked1 即是标记指针的三色标记)。
有了染色指针之后,一旦某个 Region 存活的对象被移走之后,这个 Region 就可以立即释放,而不必等待整个堆中的所有指令被修正之后才能清理。染色指针可以大幅减少垃圾回收过程中内存屏障的使用数量,设置内存屏障,尤其是写屏障的目的就是为了记录对象引用的变动情况,如果这些信息能直接维护在指针式,这样就可以减少一些专门的操作记录。
ZGC 使用了多重映射(multi-mapping)将不同的虚拟内存映射到同一物理内存地址上,这样多对一的空间映射关系,比实际使用的内存要大的多。
3 ZGC 的回收过程
ZGC 的垃圾回收过程分为四个阶段,都是可以并发执行的,其阶段分别是: 并发标记、并发预备重分配、并发重分配和并发重映射。具体的过程如下图所示:
- 1 并发标记 ,并发标记是变脸对象图做可达性分析,期间会引发短暂的系统停顿。
- 2 并发预备重分配, 这个阶段需要根据特定的条件查询并统计需要清理的 Region 信息。
- 3 并发重分配, 这个是垃圾回收的核心阶段,需要重新分配存活的对象到新的 Region 上,并且为重分配的每个 Region 维护一个并发转移表,用来记录旧对象到新对象的转移关系。
- 4 并发重映射, 就是修正整个对症指向旧对象的引用,
4 ZGC 的优缺点
ZGC 的优点是实现了高吞吐和低延迟,尤其是面对 MUMA,即非统一内存访问架构,面对 NUMA 系统架构时,则选择当前线程靠近的 CPU 进行执行回收操作,其性能表现卓越。
ZGC 的缺点是会造成浮动垃圾,ZGC 垃圾回收由于是低延迟,低停顿,这就会导致大量垃圾来不及回收完全,就会产生大量的浮动垃圾。
5 总结
在本文中总结了 ZGC 垃圾回收器的一些内容,从内存分配概念到垃圾回收的过程,最后分析了 ZGC 垃圾回收器的优缺点,对于垃圾回收器的了解又多了一些认识。