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

ゲームラグ白書 › L10 メモリ

GCスラッシング(ヒープの空き不足) GC thrashing (heap nearly full)

原因ID mem-gc-thrash · 主担当 ゲーム開発チーム・サーバー開発 · 副担当 インフラチーム・サーバーインフラ

図と実験のあるメインページでこのカードを開く →

生存データがヒープの上限に近づくと、GCが走っても回収できるものがほとんどなく、GCが休みなく繰り返されます。

なぜ イベントでの人数増加やリークで、生存データがヒープの上限近くまで埋まる → すると GCがわずかしか回収できず、すぐにまたFull GC、CPUの大半をGCが使う → 画面では サーバー全体が数分間スローモーション・フリーズを繰り返し、メモリ不足で終了

症状
スローモーション, フリーズ, 切断
要因
ストール
誰に起きるか
サーバー全体
いつ
夜のピーク時間帯, 人が集中したとき, 長時間稼働するほど
担当
主担当 ゲーム開発チーム・サーバー開発 · 副担当 インフラチーム・サーバーインフラ
ゲーム開発チームの対応
ヒープをピーク時の生存データより余裕をもって(通常2倍以上)設定、長く参照し続けるデータ・リークの削減。
インフラチームの対応
GC時間比率のアラート、粘らずに早めに再起動、ヒープを増やせるようメモリに余裕のあるインスタンス。
数値の目安
実行時間の10%を超えてGCに使っていれば、一般に危険信号とみなします。Javaの一部のGCは、時間の98%をGCに費やしてもほとんど回収できないとメモリ不足のエラーを出します。
グラフでは
上限で頭打ち · GC直後のヒープ、GC時間比率
確認箇所
GC直後に残ったヒープが最大ヒープにどれだけ近いかと、GCに使った時間の比率を確認。Javaは-Xlog:gcの行の「GC後(ヒープサイズ)」とPause Full行の頻度、.NETはdotnet-counters(.NET 8以前は% Time in GC since last GC、.NET 9以降はdotnet.gc.pause.timeの増加量)、GoはGODEBUG=gctrace=1の行と行の間隔を確認
該当する場合
GC直後もヒープが最大値近くまで残り、Full GCが立て続けに走り、GC時間比率が普段より大きく(通常10%超)上がる。その間サーバー全体のティックがそろって遅くなる
該当しない場合
GC直後のヒープに余裕があるのに停止だけが長いなら、GC方式・設定側(mem-gc)
確認手段
インフラのツールで確認(ゲームコード不要)

出典

  1. The Parallel Collector Oracle
    パラレルGCは全体時間の98%超をGCに費やしてもヒープの回収が2%未満だとOutOfMemoryError
  2. Garbage-First Garbage Collector Tuning Oracle
    G1はデフォルト(GCTimeRatio=12)でGC時間を全体の約8%以下に抑えるようヒープサイズを決める、ヒープ占有率が高すぎて起きたFull GCはログのPause Full (G1 Compaction Pause)で見つける
  3. A Guide to the Go Garbage Collector Go
    デフォルトのGOGC=100では目標ヒープが生存ヒープの約2倍、メモリ上限に張り付くとGCが休みなく走るスラッシング、GODEBUG=gctrace=1でGCトレースを出力
  4. Garbage Collector Implementation Oracle
    -Xlog:gcの行はGCの種類(Pause Young、Pause Full)と「GC前の使用量->GC後の使用量(ヒープサイズ)」、停止時間
  5. dotnet-counters diagnostic tool .NET
    .NET 9以降はdotnet.gc.pause.time、.NET 8以前は% Time in GC since last GCで表示

あわせて読みたい原因

同じ層:L10 メモリ

同じ症状(スローモーション)を起こすほかの層の原因

図と実験のあるメインページでこのカードを見る