ZGC 垃圾收集器
特点
JDK11中推出。
GC 停顿时间很短,不分代(在JDK21中引入了分代模式)。
怎么分配内存的
内存块分为三种类型:
- small:2MB,存放小于256KB的对象
- medium:32MB,存放
[256KB,4MB)的对象 - large:大小不固定,2*n MB(n>=2)。为单一对象单独分配,存放大于等于4MB的对象
ZGC 使用64位的地址,不允许开启指针压缩。JVM的指针压缩是指,使用32位地址实现更大容量的内存管理。比如32位原本能表示2^32 byte的内存,每个地址表示一个byte,指针压缩就是让一个地址表示多个byte,并且在对象不是整数倍的情况给对象加上padding。
ZGC的地址是18位未使用+4位标记+42位对象地址。(称为染色指针,42位地址能管理最多4TB,ZGC也支持43和44的)。而其它GC gc相关标记是放在对象头的markword中的。
4位标记分别是:
- finalizable
- remapped
- marked1
- marked2
remapped、marked1、marked2是指针的三种颜色。
当创建一个对象后,它会有三个地址,分别是这三种颜色。
当从堆中读取一个引用的时候(例如读取某个对象的某个引用字段),JVM会插入load barrier,返回实际的引用,因为这个引用所指向的对象可能在gc过程中被移动了。
怎么回收内存的
- 初始标记(STW): 标记 GC Roots
- 并发标记:初始状态下对象都是remapped的地址,当并发标记中如果对象的引用发生变化,那地址使用的是marked。所以这个阶段结束后marked的对象都是活跃对象。
- 再标记(STW):
- 并发转移准备:确定需要转移的区块
- 初始转移(STW):转移GC Roots的对象
- 并发转移:如果对象被访问过,那么标记为remapped
相关的 JVM 参数
ZGC的参数简单。
- 堆大小: -Xmx。当分配速率过高,超过回收速率,造成堆内存不够用时,会触发Allocation Stall,这个类Stall会减缓当前的用户线程。因此,当我们在GC日志中看到Allocation Stall,通常可以认为堆空间偏小或者concurrent gc threads数偏小。
- GC触发时机: ZAllocatioSpike Tolerance,ZCollectionInterval。ZAllocationSpikeTolerance 用来估算当前的堆内存分配速率,在当前剩余的堆内存下,ZAllocationSpike Tolerance越大,估算的达到OOM的时间越快,ZGC就会更早地进行触发GC。ZCollectionInterval用来指定GC发生的间隔,以秒位单位触发GC
- GC线程: ParallerGCThreads,ConcGCThreads。ParallelGCThreads是设置STW任务的GC线程数,默认为CPU个数的60%;ConcGCThreads是并发阶段GC线程的数目,默认为CPU个数的12.5%。
参考
https://mikechen.cc/16719.html
http://www.lihuibin.top/archives/a87613ac/#ZGC%E8%AF%9E%E7%94%9F%E8%83%8C%E6%99%AF