bigywater.tech
Java · 294

G1 Remembered Set:跨 Region 引用如何被追踪

老年代里的对象指向新生代时,G1 怎么在年轻代暂停里找到它们?这篇制造不同数量的老→新引用,读 GC 日志里的卡数与阶段耗时,看暂停是怎么变长的。

3.84 → 10.27 ms
每轮老→新引用从 0 增到 40 万时的年轻代平均暂停
≈ 6.5 万
本例脏卡数的上限(800 万槽的数组)
9
G1ConcRefinementThreads 默认值(本机)

引用数量与暂停

实测 · 本机执行输出
  老→新引用 0 个/轮        年轻代暂停 11 次:平均暂停   3.84 ms;Merge Heap Roots  0.04 ms;Scan Heap Roots(各线程平均) 0.00 ms;脏卡         2;扫描的卡         2
  1000 个/轮           年轻代暂停 11 次:平均暂停   3.91 ms;Merge Heap Roots  0.06 ms;Scan Heap Roots(各线程平均) 0.28 ms;脏卡      6549;扫描的卡      6548
  50000 个/轮          年轻代暂停 13 次:平均暂停   6.46 ms;Merge Heap Roots  0.22 ms;Scan Heap Roots(各线程平均) 2.39 ms;脏卡     60080;扫描的卡     60080
  400000 个/轮         年轻代暂停 19 次:平均暂停  10.27 ms;Merge Heap Roots  0.30 ms;Scan Heap Roots(各线程平均) 4.81 ms;脏卡     64985;扫描的卡     62482

一次暂停的日志

实测 · 本机执行输出
  GC(4)  Pre Evacuate Collection Set: 0.11ms
  GC(4)  Merge Heap Roots: 0.21ms
  GC(4)  Prepare Merge Heap Roots: 0.00ms
  GC(4)  Remembered Sets (ms):  Min: 0.00, Avg: 0.00, Max: 0.00, Diff: 0.00, Sum: 0.02, Workers: 9
  GC(4)  Merged Cards  Min: 16, Avg: 16.0, Max: 16, Diff: 0, Sum: 144, Workers: 9
  GC(4)  Dirty Cards:  Min: 1314, Avg: 6702.7, Max: 11031, Diff: 9717, Sum: 60324, Workers: 9
  GC(4)  Skipped Cards:  Min: 0, Avg:  0.0, Max: 0, Diff: 0, Sum: 0, Workers: 9
  GC(4)  Evacuate Collection Set: 6.03ms
  GC(4)  Scan Heap Roots (ms):  Min: 2.11, Avg: 2.18, Max: 2.39, Diff: 0.27, Sum: 19.62, Workers: 9
  GC(4)  Scanned Cards:  Min: 3628, Avg: 6702.7, Max: 9245, Diff: 5617, Sum: 60324, Workers: 9
  GC(4)  Scanned Blocks:  Min: 160, Avg: 425.6, Max: 968, Diff: 808, Sum: 3830, Workers: 9
  GC(4)  Post Evacuate Collection Set: 0.16ms
  GC(4)  Redirtied Cards:  Min: 1024, Avg: 4450.9, Max: 8219, Diff: 7195, Sum: 40058, Workers: 9
  GC(4) Pause Young (Normal) (G1 Evacuation Pause) 189M->173M(1024M) 6.749ms

相关参数

实测 · 本机执行输出
  JDK 21: {'G1ConcRefinementThreads': '9', 'G1RSetUpdatingPauseTimePercent': '10'}
  JDK 27: {'G1ConcRefinementThreads': '9', 'G1RSetUpdatingPauseTimePercent': '10', 'G1RemSetArrayOfCardsEntries': '16', 'G1RemSetHowlMaxNumBuckets': '8'}

分步演示

G1 的 Remembered Set
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK(Temurin 17.0.20、Homebrew 21.0.12 与 27,每篇注明实际用的版本);用 javac 编译、java 直接运行,需要第三方库时用 Maven 解析依赖;计时用 System.nanoTime,数字每次运行会有小幅抖动。JDK 21.0.12 与 27(仅 PrintFlagsFinal),Apple Silicon 9 个 GC 线程;每种配置 11–19 次暂停取平均,数字在重复运行间有约 ±0.05 ms 的波动
    • 没有验证:记忆集本身占用的内存(没有用 NMT 量)、并发 refinement 线程的实际工作量(没有开 gc+refine 日志)、Howl 等记忆集粒度变化的触发条件、卡的字节数(只从脏卡数上限与数组大小推断,没有直接量)、JDK 27 的暂停数据
    京ICP备2026067502号-1京公网安备11010502063487号