JVMのGC 実践ガイド 中編(jstatの使い方と見方)

パフォーマンスチューニング
スポンサーリンク
google.com, pub-5238665064291805, DIRECT, f08c47fec0942fa0

1.はじめに

  • 目的はjstatでGCを観測し、数字を読めるようになることです。
  • 対象はJava 21。GCはG1ZGCを中心に説明します。
  • 基本は -gcutil(利用率%)と -gc(サイズ=KB)の使い分け。-t(Timestamp列)/-h(ヘッダー再表示)で長時間観測を読みやすくする。
  • まずは Young周期Old張り付きFGCGCTの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 / S1Survivor 0/1 使用率(%)生存率の傾向(昇格増の兆候)
    EEden使用率(%)Young GC の周期把握
    OOld使用率(%)Old の張り付き/逼迫
    M / CCSMetaspace / Compressed Class Space使用率(%)クラスロード過多の兆候
    YGC / YGCTYoung GCの回数 / Young GCに要した時間の合計(秒)Young GCコストの目安
    FGC / FGCTFull 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.見方:基本

    1. Youngの周期をつかむ
      E が上昇 → Young 発生 → E が下がる。この**間隔(秒)**が割当レートと Eden サイズの釣り合い。
    2. Old の挙動をみる
      Oなだらかに上昇し、並行マーク後の Mixed段階的に下降するのが理想。
    3. コスト感を測る
      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 平均ポーズ時間の推定

    • YGCTYoung GC の累積停止時間(秒)
    • 区間の平均 Youngポーズ ≒ ΔYGCT / ΔYGC(Youngが複数回なら回数で割る)
    • 例:YGCT が 0.090 → 0.120(+0.030s)、その間に Young が 1 回なら ≈ 30ms/回

    4.4 しきい値の考え方(目安)

    観点目安
    GCT / 稼働時間5%未満(Web/API の一般目安)
    FGC0回(発生したら最優先で理由特定)
    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の混入理由を探る入口)

    9.参考リンク

    コメント

    タイトルとURLをコピーしました