共计 2567 个字符,预计需要花费 7 分钟才能阅读完成。
参考 http://cr.openjdk.java.net/~p…
https://tech.meituan.com/2020…
ZGC 收集器
ZGC 全称 Z Garbage Collector。是由 Oracle 公司研发的,在 2018 年提交给 OpenJDK 的,基于 JDK11 的一款垃圾收集器。
ZGC 的指标
ZGC 的指标是在尽可能对吞吐量(吞吐量与进展工夫成反比)影响不大的前提下,实现在任意堆大小下都能够把垃圾收集的进展(Stop The World)工夫限度在十毫秒以内的低提早。
ZGC 的 Region
ZGC 采纳基于 Region 的内存布局(也有一些材料称为 Page 或者 ZPage),ZGC 的 Region 具备动态性,动态创建和销毁,以及动静的区域容量大小。在 x86 架构下,ZGC 的 Region 分为大、中、小三类容量:
- 小型 Region(Small Region):容量固定为 2MB,用于搁置小于 256KB 的小对象。
- 中型 Region(Medium Region):容量固定为 32MB,用于搁置大于等于 256KB 但小于 4MB 的对象。
- 大型 Region(Large Region):容量不固定,能够动态变化,但必须为 2MB 的整数倍。用于搁置 4B 或以上的大对象。每个大型 Region 中只会寄存一个大对象。
染色指针
染色指针(Colored Pointer)是 ZGC 的核心技术,理解 ZGC 的运作过程前,先来理解下染色指针。
ZGC 的染色指针,是一种间接将大量额定信息存储在指针上的技术。
ZGC 仅反对 64 位零碎。在 64 位零碎中,高 18 位不能用来寻址,残余的 46 位能够被用来寻址,ZGC 将这 46 位中的高 4 位(ZGC 将对象存活信息存储在 42~45 位中)提取进去存储四个标记位,通过这些标记位,虚拟机能够间接从指针中看到其援用对象的三色标记状态、是否进入了重调配集(即被挪动过)、是否只能通过 finalize()办法能力拜访到。这种形式进一步压缩了只有 46 位的地址空间,导致 ZGC 可能治理的内存不能够超过 4TB。
在对象创立时,ZGC 同时会为该对象在 M0、M1 和 Remapped 地址空间别离申请一个虚拟地址,且这三个虚拟地址对应同一个物理地址,但这三个空间在同一时间有且只有一个空间无效。在对象被 ZGC 标记过程中,这三个空间将会产生切换,这里就不详细描述切换过程了。
这时,可达性剖析遍历对象图来标记对象,能够说是遍历“援用图”来标记“援用”了。
读屏障
读屏障是 JVM 向利用代码插入一小段代码的技术。当利用线程从堆中读取对象援用时,就会执行这段代码。须要留神的是,仅“从堆中读取对象援用”才会触发这段代码。
Object o = obj.FieldA // 从堆中读取援用,须要退出屏障
<Load barrier>
Object p = o // 无需退出屏障,因为不是从堆中读取援用
o.dosomething() // 无需退出屏障,因为不是从堆中读取援用
int i = obj.FieldB // 无需退出屏障,因为不是对象援用
在 ZGC 中,利用线程拜访对象将触发“读屏障”,如果发现对象被挪动了,那么“读屏障”会把读出来的指针更新到对象的新地址上,这样利用线程始终拜访的都是对象的新地址。
ZGC 的运作过程
四大阶段
ZGC 采纳标记 - 复制算法。ZGC 的运作过程分为 4 大阶段,其中 ZGC 把第一阶段 Mark 和最初一阶段 Remap 合并了(稍后解说合并起因)。
- 并发标记(Concurrent Mark):遍历对象图做可达性剖析,但 ZGC 的标记是在指针上进行的,标记阶段会更新染色指针中的 Marked0、Marked1 标记位。标记过程是针对全堆的。
- 并发准备重调配(Concurrent Prepare for Relocate):这个阶段须要依据特定的查问条件统计得出本次收集过程要清理哪些 Region,将这些 Region 组成调配集(Relocation Set)。ZGC 每次回收都会扫描所有的 Region。
- 并发重调配(Concurrent Relocate):重调配是 ZGC 执行过程中的外围阶段,这个过程要把重调配集中的存活对象复制到新的 Region 上,并为重调配集中的每个 Region 保护一个转发表(Forward Table),记录从旧对象到新对象的转向关系。
- 并发重映射(Concurrent Remap):重映射所做的就是修改整个堆中指向重调配集中旧对象的所有援用。这个操作要遍历对象图,所以 ZGC 将此过程合并到了下一次垃圾收集循环的并发标记阶段,省去了一次遍历对象图的开销。
指针的自愈能力:
在并发重调配阶段,保护转换表的过程中,如果用户线程在此时并发拜访了位于重调配集中的对象,这次拜访将会被预置的内存屏障所截获,而后立刻依据 Region 上的转发表记录将此拜访转发到新复制的对象上,并同时修改更新该援用的值,使其间接指向新对象,ZGC 将这种行为称为指针的“自愈(Self-Healing)”能力。这样做的益处是只有第一次拜访旧对象会陷入转发,也就是只慢一次。
这四个大阶段总的进展工夫小于 10ms。
具体过程:
ZGC 的具体 GC 过程只有三个 STW(Stop The World)阶段:初始标记 , 再标记 , 初始转移。其中,初始标记和初始转移别离都只须要扫描所有 GC Roots,其解决工夫和 GC Roots 的数量成正比,个别状况耗时十分短;再标记阶段 STW 工夫很短,最多 1ms,超过 1ms 则再次进入并发标记阶段。即,ZGC 简直所有暂停都只依赖于 GC Roots 汇合大小,进展工夫不会随着堆的大小或者沉闷对象的大小而减少
ZGC 触发机会
次要是 基于调配速率的自适应算法,其余形式暂且不提。
算法原理可简略形容为”ZGC 依据近期的对象调配速率以及 GC 工夫,计算出当内存占用达到什么阈值时触发下一次 GC”。日志中关键字是“Allocation Rate”
一次残缺的 GC 日志
ZGC 的优缺点
长处
- 进展工夫不超过 10ms;
- 进展工夫不会随着堆的大小,或者沉闷对象的大小而减少;
- 反对 8MB~4TB 级别的堆(将来反对 16TB)
ZGC 实用于大内存低提早服务的内存治理和回收
毛病
能接受的对象调配速率不能太高。
对象调配速率高,将发明大量的新对象,这些新对象很难进入当次收集的标记范畴,只能当做存活对象,这就产生了大量的浮动垃圾。每次回收到的内存小于浮动垃圾所占的空间大小,堆中的可用空间就越来越小了。