Metronome GC:確定性即時垃圾收集器核心機制與調優指南
傳統 Stop-The-World GC 導致不可預測暫停,不適合即時系統。Metronome 採用增量式量子收集、滑動視窗利用率保證、Arraylet 記憶體佈局、協作式暫停機制、SATB 寫入屏障,實現微秒級確定性暫停。本文深度解析核心技術與調優實戰。
傳統 GC 與即時系統衝突
STW 暫停特徵

- 應用耗盡堆 → 暫停所有應用執行緒 → 完整 GC → 恢復應用
- 暫停頻率與持續時間**不可預測**
- 標記階段:遍歷所有存活物件,耗時隨物件圖複雜度變化
- 清除階段:回收死物件空間,耗時隨堆碎片狀態變化
即時系統需求
- 硬即時:超時 = 災難性失敗 (心臟監測、國防系統)
- 軟即時:超時 = 功能降級 (GUI 幀率下降)
- 核心指標:暫停時間上界 與 應用程式利用率
Metronome 核心創新
1. 增量式量子收集

- 將 GC 循環分解為固定大小**量子** (預設 500 微秒)
- 每量子:搶占應用 → 執行 GC 工作 → 歸還應用
- 避免單一長暫停,但需保證應用獲得足夠執行時間
2. 滑動視窗利用率保證

- 應用程式利用率:時間視窗內應用連續執行佔比
- 預設:10ms 視窗、500μs 量子、70% 目標利用率
- 每視窗最多 6 個 GC 量子,最少 14 個應用量子
- 每 GC 量子後**強制**歸還至少 1 個應用量子
- 利用率 < 50% 時允許連續 GC 量子
利用率動態圖解


- A 區:梯形下降 = GC 與應用交錯
- B 區:應用獨佔 (GC 閒置)
- C 區:鋸齒狀 = 維持目標利用率
- D 區:上升 = GC 完成,應用恢復 100%
3. Arraylet 解決大物件分配碎片問題

- 傳統壓縮整理耗時不可預測
- Arraylet 將陣列分解為:**Spine (中央物件) + 多個 Leaf (資料分塊)**
- Leaf 固定大小、獨立分配、堆中任意分佈
- Spine 包含尾部資料優化內部碎片
- 避免大陣列分配失敗觸發同步 GC
4. 協作式暫停機制
- Alarm 執行緒:最高優先級,500μs 喚醒,決定是否調度 GC 量子
- GC 執行緒:執行實際 GC 工作,優先級高於一般 RT 執行緒,低於 NHRT
- 暫停流程:Alarm 暫停 JVM → 喚醒 GC → GC 工作 → GC 休眠 → JVM 恢復
- Java 執行緒週期性檢查暫停請求:釋放 JVM 結構 → 儲存物件引用 → 回報安全點 → 休眠
5. SATB (Snapshot-At-The-Beginning) 寫入屏障

- 問題:GC 標記期間應用修改引用,導致物件「隱藏」被誤回收
- 方案:記錄所有欄位寫入的**舊值**,視為額外根引用保護
- Yuasa 風格屏障:保留槽位原始值,標記為存活
- JNI 全域引用列表同樣需屏障保護
6. 根掃描優化
- 堆疊原子掃描:單一執行緒堆疊必須在單一量子內完成掃描
- 模糊屏障:未掃描堆疊的執行緒,屏障追蹤寫入/讀出值
- 建議:避免深層遞迴調用導致堆疊過大
Metronome 調優實戰
堆大小與利用率平衡關係

- 高利用率需要大堆支撐
- 分配率高 + 利用率高 → 記憶體耗盡 → 同步 GC (利用率歸零)
- 調優策略:降低目標利用率、增加堆大小、或兩者結合
Verbose GC 分析
<gc type="heartbeat" quantumcount="477">
<quantum minms="0.078" meanms="0.503" maxms="1.909" />
<heap minfree="262144000" meanfree="265312260" maxfree="268386304" />
<immortal minfree="14570208" meanfree="14570208" maxfree="14570208" />
</gc>
synchgc:同步 GC (System.gc() 或 OOM),應避免
trigger start/end:GC 循環邊界
quantum maxms:監控最大暫停是否超過即時需求
- 堆自由空間趨勢:穩定 = 良好,遞減 = 記憶體洩漏
TuningFork 視覺化分析工具

- 離線/即時分析 GC 追蹤日誌
- 顯示利用率、堆使用、各階段耗時
使用 Metronome 注意事項
| 風險 | 現象 | 對策 |
| 永久記憶體 | 類別不卸載,永久區持續增長 | 適當調整永久區大小、避免動態大量生成類別 |
| 系統時間同步 | NTP 時間跳躍導致利用率失效/OOM | 避免執行期間同步硬體時鐘 |
| 多 JVM 干擾 | Alarm/GC 執行緒搶占其他 JVM 應用執行緒 | 單機單 JVM、或 CPU 親和性綁定 |
| 根結構濫用 | JNI 全域引用/深堆疊導致掃描超時 | 限制 JNI 引用數量、避免深度遞迴 |
RTSJ 整合:NHRT 繞過 GC
- RealtimeThread:高優先級、受 GC 影響
- NoHeapRealtimeThread (NHRT):禁止引用堆物件,**完全不受 GC 暫停影響**
- Immortal/Scoped Memory:NHRT 專用記憶體區域
- 適用:極致確定性需求,但開發複雜度極高
結語
Metronome 通過工程權衡 (增量量子、利用率保證、Arraylet、協作暫停、SATB) 實現**確定性 GC**,滿足多數軟即時需求。硬即時系統可結合 NHRT 繞過 GC,但需承擔非堆程式設計複雜度。調優核心在於「堆大小 ↔ 利用率 ↔ 分配率」三角平衡,需實測迭代尋找最佳點。