遊戲 Lag 白皮書 › L10 記憶體
GC thrashing(heap 可用空間不足) GC thrashing (heap nearly full)
原因 ID mem-gc-thrash · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
在含圖解與實驗的完整版中開啟卡片 →
存活資料逼近 heap 上限時,每次 GC 幾乎回收不到東西,GC 就會不停反覆執行。
為什麼 活動湧入的人潮或記憶體洩漏,讓存活資料逼近 heap 上限 → 於是 GC 只能回收一點點,馬上又進行 Full GC,CPU 大部分都被 GC 占用 → 畫面上 整個伺服器在幾分鐘內反覆出現慢動作與定格,最後因記憶體不足而終止
- 症狀
- 慢動作, 定格, 斷線
- 因素
- 停滯
- 誰會遇到
- 整個伺服器
- 何時
- 晚間尖峰時段, 人潮湧入時, 開越久越嚴重
- 負責單位
- 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
- 遊戲開發團隊要做的事
- 把 heap 設得比尖峰時的存活資料寬裕(通常 2 倍以上)、減少長期被參考的資料與洩漏。
- 基礎設施團隊要做的事
- 設定 GC 時間比例警示;發生時不要硬撐,儘快重新啟動;選用記憶體充裕、可以加大 heap 的執行個體。
- 數值參考
- GC 占用超過 10% 的執行時間,通常就視為危險訊號。Java 的部分 GC 若花了 98% 的時間做 GC 卻幾乎回收不到記憶體,就會丟出記憶體不足錯誤。
- 圖表上
- 碰到上限後持平 · GC 後的 heap、GC 時間比例
- 查看位置
- 看 GC 剛結束時剩下的 heap 有多接近最大 heap,以及花在 GC 的時間比例。Java 看 -Xlog:gc 行的「GC 後(heap 大小)」與 Pause Full 行出現的頻率;.NET 看 dotnet-counters(.NET 8 以下為 % Time in GC since last GC,.NET 9 以後為 dotnet.gc.pause.time 的增加量);Go 看 GODEBUG=gctrace=1 各行之間的間隔
- 符合的跡象
- GC 剛結束時 heap 仍接近上限,Full GC 接連執行,GC 時間比例明顯高於平常(通常超過 10%)。這段期間整個伺服器的 tick 一起變慢
- 不符合的跡象
- GC 後 heap 仍有餘裕、只有暫停很長時,是 GC 種類或設定的問題(mem-gc)
- 確認方式
- 用基礎設施工具確認(不需要遊戲程式碼)
出處
- The Parallel Collector Oracle
Parallel GC 若花超過總時間 98% 做 GC,卻只回收不到 2% 的 heap,就會丟出 OutOfMemoryError - Garbage-First Garbage Collector Tuning Oracle
G1 預設(GCTimeRatio=12)會調整 heap 大小,讓 GC 時間維持在總時間約 8% 以下;因 heap 占用率過高而發生的 Full GC,可從 log 中的 Pause Full (G1 Compaction Pause) 找出 - A Guide to the Go Garbage Collector Go
預設 GOGC=100 時,目標 heap 約為存活 heap 的 2 倍;貼近記憶體上限時,GC 會不停執行而陷入 thrashing;以 GODEBUG=gctrace=1 輸出 GC 追蹤資訊 - Garbage Collector Implementation Oracle
-Xlog:gc 行包含 GC 種類(Pause Young、Pause Full)、「GC 前用量->GC 後用量(heap 大小)」與暫停時間 - dotnet-counters diagnostic tool .NET
.NET 9 以後顯示為 dotnet.gc.pause.time,.NET 8 以下顯示為 % Time in GC since last GC
相關原因
同一層:L10 記憶體
同一症狀(慢動作)在其他層的原因
查看含圖解與實驗的完整版卡片