判断并发标记效率需拆解各阶段:根区域扫描反映跨代引用密度;并发标记耗时长说明对象图复杂或引用处理积压;remark耗时突增常因标记未完成而补漏;混合gc中回收集变化可验证标记效果。

看并发标记周期的执行效率,关键不是盯总耗时,而是拆解每个阶段是否卡顿、是否积压、是否被反复拉长。G1 的并发标记本身不 STW,但它的起止节奏和中间状态,直接决定混合 GC 能不能及时启动、能不能高效回收。
抓准并发标记的三个锚点日志
并发标记周期有明确的起点、主体过程和收尾信号,必须按顺序对齐:
- [GC concurrent-root-region-scan-start]:初始扫描开始,只扫根区域(通常是 Survivor 中可能引用老年代的 Region),这个阶段快慢反映 Survivor 到老年代的跨代引用密度
- [GC concurrent-mark-start] → [GC concurrent-mark-end]:真正的并发遍历阶段,耗时长说明老年代对象图复杂、引用链深或存在大量弱/软引用待处理
- [GC remark]:STW 的最终标记,它一结束,紧接着就是 Mixed GC。如果 remark 耗时突增,往往是因为 concurrent-mark 阶段没完成清理,导致 remark 被迫补漏(比如重新扫描 Dirty Card)
识别效率低下的典型日志特征
以下组合出现,基本说明并发标记“跑不动”或“跑偏了”:
- concurrent-mark-start 和 concurrent-mark-end 之间间隔远超预期(比如 >5s),且日志中穿插大量 [GC ref-proc] 或 [GC concurrent-cleanup-start] —— 表明引用处理队列积压,写屏障开销反噬标记进度
- 频繁出现 [GC concurrent-root-region-scan-end] 后紧接 [GC concurrent-mark-start],但中间夹着多次 [GC pause (G1 Evacuation Pause) (young)] —— 说明 Young GC 太密,不断打断并发标记线程调度
- remark 阶段日志里带 “No cards processed” 或 “Processed X cards” 数值极小,却耗时很长 —— 暗示 RSet 更新延迟严重,remark 不得不退化为全堆扫描
结合回收集变化验证标记效果
并发标记的最终目标是为 Mixed GC 准备高质量回收集。看它干得好不好,得回头查混合 GC 日志里的实际动作:
- 查 [G1Ergonomics (Mixed GCs) add old region to collection set] 是否稳定出现 —— 如果长期不出现,说明标记没识别出可回收的老年代 Region
- 对比连续几次 Mixed GC 的 Old regions: X->Y 变化量:若每次只释放 1~2 个 Region,且 reclaimable 字段持续低于 20%,说明标记结果不准或存活对象误判多
- 出现 Humongous regions reclaimed 但 concurrent-mark 阶段无对应扫描记录 —— 标记漏掉了巨型对象的跨代引用,导致后续回收被动触发
ZGC / Shenandoah 的对标参考
虽然它们没有“混合 GC”,但并发标记完成同样是回收前提:
- ZGC 看 “Concurrent Mark Cycle Complete” 到 “Relocation Set Selection” 的间隔:超过 100ms 就算延迟偏高,说明标记后筛选可重定位页的逻辑受阻
- Shenandoah 看 “Concurrent evacuation” 是否在 “Concurrent marking complete” 后立即启动:若中间插入多次 “Concurrent cleanup”,说明标记产出的存活数据质量差,需反复清理才能进入转移
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











