한국어English日本語简体中文繁體中文DeutschไทยTiếng ViệtРусскийPortuguês (Brasil)EspañolBahasa Indonesia

遊戲 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)
確認方式
用基礎設施工具確認(不需要遊戲程式碼)

出處

  1. The Parallel Collector Oracle
    Parallel GC 若花超過總時間 98% 做 GC,卻只回收不到 2% 的 heap,就會丟出 OutOfMemoryError
  2. Garbage-First Garbage Collector Tuning Oracle
    G1 預設(GCTimeRatio=12)會調整 heap 大小,讓 GC 時間維持在總時間約 8% 以下;因 heap 占用率過高而發生的 Full GC,可從 log 中的 Pause Full (G1 Compaction Pause) 找出
  3. A Guide to the Go Garbage Collector Go
    預設 GOGC=100 時,目標 heap 約為存活 heap 的 2 倍;貼近記憶體上限時,GC 會不停執行而陷入 thrashing;以 GODEBUG=gctrace=1 輸出 GC 追蹤資訊
  4. Garbage Collector Implementation Oracle
    -Xlog:gc 行包含 GC 種類(Pause Young、Pause Full)、「GC 前用量->GC 後用量(heap 大小)」與暫停時間
  5. dotnet-counters diagnostic tool .NET
    .NET 9 以後顯示為 dotnet.gc.pause.time,.NET 8 以下顯示為 % Time in GC since last GC

相關原因

同一層:L10 記憶體

同一症狀(慢動作)在其他層的原因

查看含圖解與實驗的完整版卡片