1.はじめに
- 目的はjstatでGCを観測し、数字を読めるようになることです。
- 対象はJava 21。GCはG1とZGCを中心に説明します。
- 基本は
-gcutil
(利用率%)と-gc
(サイズ=KB)の使い分け。-t
(Timestamp列)/-h
(ヘッダー再表示)で長時間観測を読みやすくする。 - まずは Young周期、Old張り付き、FGC、GCTの4点を見ます。
- GCの基本はこちらを参照してください(前編:GCの基本/発火タイミング)
2.jstatの基本
2.1 前提とPIDの見つけ方
- 同一ホストで対象 JVMのPIDは次で確認できます
jcmd -l # Javaプロセス一覧(PIDとメインクラス/jarが出る)
2.2 代表的な取得コマンド
# 利用率(%)中心:1秒間隔で120回(約2分)
jstat -gcutil <pid> 1000 120
# 各領域サイズ/回数:2秒間隔で30回
# ※ -gcのサイズ系(EC/OC/EU/OUなど)の単位はKB(必要に応じてMB換算)
jstat -gc <pid> 2000 30
# タイムスタンプとヘッダーを付けつつ長時間観測(5秒間隔で約50分)
jstat -gcutil -t -h10 <pid> 5000 600
# 直近/現在のGC原因も見たいとき(Full混入時の手掛かりになる)
jstat -gccause -t <pid> 5000 120
# CSV保存(例)
jstat -gcutil -t <pid> 1000 600 > jstat_gcutil.csv
- ここでは間隔を長め(5〜10秒)にしてオーバーヘッドを抑えるようにします
- 観測は立ち上げ → 安定 → クールダウンまで含めると傾向が見やすい
2.3 -gcutil
の主な列
列 | 意味 | 使いどころ |
---|---|---|
S0 / S1 | Survivor 0/1 使用率(%) | 生存率の傾向(昇格増の兆候) |
E | Eden使用率(%) | Young GC の周期把握 |
O | Old使用率(%) | Old の張り付き/逼迫 |
M / CCS | Metaspace / Compressed Class Space使用率(%) | クラスロード過多の兆候 |
YGC / YGCT | Young GCの回数 / Young GCに要した時間の合計(秒) | Young GCコストの目安 |
FGC / FGCT | Full GCの回数 / Full GCに要した時間の合計(秒) | 長停止の有無と重さ |
GCT | 全GC累積停止時間(秒) | 稼働時間に対する比率で健康度 |
2.4 -gc
の主な列(抜粋)
- EC/OC(Eden/Old 容量), EU/OU(使用量)…単位はKB(必要に応じてMB換算)
- 回数系(YGC/FGC など)は -gcutil と同様に参照
図: jstat の主要列 → 現象の対応
E (Eden%) ↑↑ -> 次の Young GCが近い(Eden満杯の兆候)
O (Old%) ↑↑ -> Mixed GCが必要 / Old逼迫の兆候
YGC/YGCT Young GCの回数 / 累積停止時間(ポーズ傾向)
FGC/FGCT Full GCの回数 / 累積停止時間(発生は要調査)
GCT 全GC累積(稼働時間に対する割合を監視)
M / CCS Metaspace / Compressed Class Spaceの使用率
3.見方:基本
- Youngの周期をつかむ
E
が上昇 → Young 発生 →E
が下がる。この**間隔(秒)**が割当レートと Eden サイズの釣り合い。 - Old の挙動をみる
O
がなだらかに上昇し、並行マーク後の Mixed で段階的に下降するのが理想。 - コスト感を測る
GCT / 観測時間
が数%以内か。FGC=0
を維持できているか。
OKサイン: YGC が適度に伸び、O(Old)が高止まりせず、FGC=0。累積 GCT は小さい。
*OKサイン: YGCが適度に伸び、O(Old)が高止まりせず、FGC=0。累積GCTは小さい。
4.見方:詳細
4.1 アロケーションレート(概算)
- 直近 Young区間のEden 使用量増分(EU の差) ÷ Young 間隔(秒)≒ 割当速度(KB/s → MB/s 換算)
- 例:Young 直後 EU=20MB 相当 → 次のYoung直前 EU=200MB 相当、間隔10秒なら
(200−20) / 10 ≒ 18 MB/s
4.2 プロモーションレート(Young → Old)
- Young 直前/直後の OU(Old 使用量)増分 ÷ Young 間隔(秒)
- 生存率が高いほど Old 増分は大きくなり、Old 張り付きの予兆になる
4.3 平均ポーズ時間の推定
YGCT
は Young GC の累積停止時間(秒)- 区間の平均 Youngポーズ ≒ ΔYGCT / ΔYGC(Youngが複数回なら回数で割る)
- 例:
YGCT
が 0.090 → 0.120(+0.030s)、その間に Young が 1 回なら ≈ 30ms/回
4.4 しきい値の考え方(目安)
観点 | 目安 |
---|---|
GCT / 稼働時間 | 5%未満(Web/API の一般目安) |
FGC | 0回(発生したら最優先で理由特定) |
Old のピーク | 80%未満を目標(連続ピークは注意) |
5.代表パターン
※ 以下は -t
指定時のTimestamp
列の例
5.1 安定な G1
Timestamp S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.0 0 0 10 40 15 10 0 0.000 0 0.000 0.000
10.0 5 0 92 42 16 10 3 0.090 0 0.000 0.090
20.0 1 4 15 41 16 10 4 0.120 0 0.000 0.120
見方: 10 秒で Young ×3、Old は滑らか、FGC=0、累積 0.12s → 健全
5.2 Young 過多(Eden 小 / 割当過多)
Timestamp E O YGC YGCT GCT
0.0 10 35 0 0.000 0.000
1.0 95 36 3 0.060 0.060
2.0 93 37 6 0.120 0.120
見方: 1 秒ごとに Young,Edenを増やす/ヒープ拡大/割当削減で周期を伸ばす
5.3 Old 張り付き(Mixed が効いていない)
Timestamp E O YGC FGC GCT
0.0 10 70 0 0 0.000
30.0 90 85 12 0 0.200
60.0 88 88 24 1 0.600
見方: Oldが高止まり → FGC発生
対処例: 昇格過多/巨大配列等を疑い、Mixed効率改善や -XX:G1ReservePercent
の増加(ヒープ拡大も併用)を検討
6.収集の注意(本番/コンテナ)
- 間隔は(5–10秒)で低オーバーヘッドにして、観測期間は立ち上げ〜安定〜終了を含める
- CI や負荷試験ジョブで自動採取 → 履歴比較を習慣化
- 実効コア数の解釈が合わない場合は
-XX:ActiveProcessorCount=<n>
を指定して安定化 jcmd <pid> GC.class_histogram
で大きいクラス/配列を把握(Impact: High。本番環境では時間/頻度に注意)
7.しきい値の目安(Web/API想定)
GCT / 稼働
< 5%FGC = 0
- Youngポーズの平均/中央値:数十ms 程度(ワークロード次第)
- Oldピークは 80%未満。連続ピーク/上昇一方は改善検討
8.まとめ
- OKライン:FGC=0、GCT/稼働が数%以内、E%は周期的に上下、O%は高止まりしない。
- 算術の型:割当速度=ΔEU/Δt、昇格=ΔOU/Δt、平均Youngポーズ=ΔYGCT/ΔYGC。
- 収集の補助:
jcmd -l
でPID確認、jstat -gccauseで直近/現在のGC原因、jcmd GC.class_histogram
で巨大配列/キャッシュの当たりを付ける(本番環境は実行頻度に注意)。 - ZGCの読み方:停止は小さく出やすい。
E/O%
の解釈はG1ほど意味を持たないため、**停止時間とアプリ指標(p99/CPU)**の相関で評価。
覚えておくと便利なオプション
-t
… 起動からの経過秒を Timestamp列として付与-hN
… N行ごとにヘッダー再表示(長時間観測や目視確認で便利)-gcutil
… % 中心-gc
… サイズ中心(KB)-gccause
… 直近/現在のGC原因も出力(Fullの混入理由を探る入口)
コメント