ZGC的Marked0、Marked1、Remapped视图本质是同一物理内存的三种虚拟地址别名,通过指针高4位颜色位标识,配合读屏障实现并发标记与重映射;其中Marked0/Marked1交替用于双缓冲标记避免漏标,Remapped为稳定终态,标识对象已完成转移且引用已更新。

Marked0、Marked1、Remapped 视图的本质是地址空间的元数据标记位
ZGC 中的三种视图不是独立内存区域,而是对同一物理内存地址施加的不同“解读方式”。每个对象头(Mark Word)中预留了 2 位(称为 color bits),用于标识该对象当前所属的视图:
- 00 → Marked0 视图
- 01 → Marked1 视图
- 10 → Remapped 视图
(11 是保留值,不使用)
JVM 通过原子操作翻转这些位来切换视图,无需移动对象、也不需更新所有引用,实现并发标记与重映射。
回收周期中三者如何协同切换
ZGC 采用“染色-转移-重映射”三阶段循环,视图切换严格绑定于 GC 周期状态:
- 初始状态(Idle / 新分配):所有新对象默认进入当前的 Marked0 视图(假设本轮以 Marked0 为起点)
- 并发标记阶段:遍历对象图,将存活对象从 Remapped(上一轮结果)或初始未标记态,统一染色为当前标记视图(如 Marked0)。此时 Marked0 表示“本轮已标记存活”
- 并发转移阶段:将 Marked0 中部分存活对象复制到新页;转移完成后,原位置对象头被设为 Remapped(表示“已转移,旧地址失效”),新对象头初始化为 Marked1(作为下一轮标记起点)
- 并发重映射阶段:将程序中仍指向旧地址的引用(通过读屏障拦截),逐步更新为新地址,并将对应对象头从 Marked1 切换为 Remapped —— 此时 Remapped 表示“已完成重映射,可安全访问”
为什么需要两个 Marked 视图(Marked0/Marked1)
双标记视图解决的是“跨周期标记连续性”问题:
- 若只用一个 Marked 视图,当 GC 周期未完成而新周期启动时,无法区分“上轮未处理完的标记”和“本轮新标记”,导致漏标或重复处理
- Marked0 和 Marked1 交替使用(类似双缓冲),确保每轮 GC 都有专属标记空间。例如:第 N 轮用 Marked0 标记,第 N+1 轮自动切到 Marked1,天然隔离标记状态
- Remapped 是唯一“稳定终态”视图,代表该对象已完成转移且引用已更新,可被后续任意轮次直接识别为存活并跳过重新标记
读屏障如何配合视图切换工作
ZGC 所有对象引用访问都经过读屏障(Load Barrier),其核心职责就是按需触发视图检查与重映射:
- 当代码读取一个引用时,读屏障检查目标对象头 color bits
- 若为 Marked0 或 Marked1,说明该对象可能尚未重映射,屏障会暂停当前线程,将该引用更新为新地址,并把对象头改为 Remapped
- 若已是 Remapped,则直接返回引用,无额外开销
- 这一机制让重映射过程可以完全并发、渐进式进行,不必等待 STW


















