参考 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实用于大内存低提早服务的内存治理和回收
毛病
能接受的对象调配速率不能太高。
对象调配速率高,将发明大量的新对象,这些新对象很难进入当次收集的标记范畴,只能当做存活对象,这就产生了大量的浮动垃圾。每次回收到的内存小于浮动垃圾所占的空间大小,堆中的可用空间就越来越小了。