Refine线程池含G1ConcRefinementThreads+1个线程:1个专做新生代RSet抽样以调控YHR数量满足停顿目标,其余负责并发消费DCQ更新RSet;DCQ由写屏障填充、DCQS统一调度,各Refine线程绑定固定DCQ以减少竞争;RSet更新异步解耦,Mutator可协助消费,GC线程按需介入,兼顾低延迟与准确性。

G1中的Refinement线程池专门负责异步、并发地消费Dirty Card Queue(DCQ),避免RSet更新阻塞Mutator线程,是G1实现低延迟GC的关键设计之一。
Refinement线程池的组成与职责分工
Refinement线程池默认包含 G1ConcRefinementThreads + 1 个线程。其中:
- 一个线程专用于新生代RSet抽样(
run_young_rs_sampling),动态调整YHR(Young Heap Region)数量,以满足用户设定的停顿时间目标(如-XX:MaxGCPauseMillis); - 其余线程(即G1ConcRefinementThreads个)专职处理DCQ,更新对应Region的记忆集RSet;
- 每个Refinement线程绑定固定的一组DCQ(由DCQS统一管理),不跨队列争抢,减少锁竞争。
DCQ如何被填充与分发
脏卡产生源于写屏障(Write Barrier):当Mutator线程修改对象引用时,若该引用跨越Region边界(如老年代对象指向新生代对象),写屏障会将对应卡页(Card,512字节)标记为“脏”,并把其地址压入当前线程本地的DCQ中。
- 每个Java线程维护自己的DCQ,避免并发写冲突;
- 所有本地DCQ由全局Dirty Card Queue Set(DCQS)统一注册和调度;
- 当本地DCQ满或达到阈值,会触发“转移”动作,将其归还给DCQS供Refinement线程消费。
RSet更新的异步性与协作机制
RSet更新不是即时同步完成的,而是通过DCQ中转实现解耦:
- Refinement线程从分配给它的DCQ中批量取出脏卡,解析卡内对象引用,定位被引用的Region,并将源Region信息加入目标Region的RSet;
- 若Refinement线程处理滞后(如DCQ积压),Mutator线程会在写屏障中触发“退化处理”:主动帮助消费部分DCQ(称为“refinement assistance”),防止队列溢出导致暂停;
- GC线程在初始标记或并发标记阶段,也可能直接扫描部分DCQ,加速RSet就绪,确保STW阶段无需再遍历整个老年代。
为什么需要这种异步并发设计
同步更新RSet会导致写屏障开销剧增,严重拖慢Mutator吞吐;而全靠GC线程处理又会造成STW延长。Refinement线程池的设计实现了三重平衡:
- 写屏障只做轻量级标记和入队,保证Mutator响应快;
- Refinement线程后台持续消化,使RSet逐步趋近准确;
- GC线程按需介入,兼顾精度与停顿可控性。

















