JVM, メモリー状況取得, 障害対応
コマンドいろいろ
- Java VM の設定一覧詳細を表示
java -XX:+PrintFlagsFinal -version -server
- jps
Javaプロセス一覧
- jstack
スレッドダンプ取得
jstack <プロセスID>プロセスID>
- jmap
- ヒープ使用状況、ヒープ設定パラメータ(NewRatio, SurvivorRatioなど)
jmap -heap <プロセスID>プロセスID>
- ネイティブメモリー使用状況
jmap <プロセスID>プロセスID>
- ヒープダンプ
jmap -dump:format=b,file=heap.dump <プロセスID>プロセスID>
- jinfo
- JVM設定表示
jinfo <プロセスID>プロセスID>
- フラグ設定値だけを表示
jinfo -flags <プロセスID>プロセスID>
- フラグ設定値を変更
jinfo -flag key=value <プロセスID>プロセスID>
- lsof(Linuxコマンド)
参照ファイル一覧
lsof <プロセスID>
lsof -u ユーザーIDプロセスID>
- jstat
- 統計情報出力
param=”-class -compiler -gc -gccapacity -gccause -gcmetacapacity -gcnew -gcnewcapacity -gcold -gcoldcapacity -gcutil -printcompilation”; for p in $param; do echo $p; jstat $p `jps | grep <メインクラス名> | awk '{print $1;}'\`; doneメインクラス名>
- 上のコマンドをタブ区切りにする
param=”-class -compiler -gc -gccapacity -gccause -gcmetacapacity -gcnew -gcnewcapacity -gcold -gcoldcapacity -gcutil -printcompilation”; for p in $param; do jstat $p `jps | grep MainKt | awk ‘{print $1;}’` | sed ‘s/^ *//’ | sed ‘s/ */\t/g’; done > hoge.txt
- 日付付きで GC ログ出力(ヘッダーは出力しない)
echo -n date +%Y/%m/%d-%H:%M:%S
” “ » gc.log
jstat -gc `jps | grep MainKt | awk ‘{print $1;}’` | sed -e ‘/S0C.*/d’ | sed ‘s/^ *//’ | sed ‘s/ */\t/g’ » gc.log
- jcmd
重要: 対象 Javaプロセスを実行しているのと同じユーザで実行する
- 診断情報を出力
jcmd <プロセスID|メインクラス名> PerfCounter.print
「sun.rt.createVmBeginTime」の数値が起動時刻になるのかも。
(例) sun.rt.createVmBeginTime=1531354125170 の場合
System.out.println( new Date( 1531354125170 ));
- すべてのパラメーターを一覧を表示
jcmd <プロセスID> VM.flags -allプロセスID>
- Full GC を実行
jcmd <プロセスID> GC.runプロセスID>
- プロセスに対して使用可能なコマンド一覧を表示
jcmd <プロセスID|メインクラス名> help
- jstack の出力結果をファイルに保存して、スレッド名の一覧を抽出
- jps でプロセス ID を確認
- プロセスID を指定して取得した jstack の実行結果を、日時別のファイルに保存
jstack <PID> jstack-$(date +%Y%m%d%H%M%S).txt
- 出力されたファイルから不要な行や文字列を取り除いて、スレッド名だけを抽出し、大文字・小文字を無視して並び替え
grep -E '^"' jstack-20250107091530.log | sed -e 's/" ..*$//' | sed -e 's/^"//' | sort -f
- または直接フィルタ
jstack <PID> | grep -E '^"' | sed -e 's/" ..*$//' | sed -e 's/^"//' | sort -f
ヒープ
ヒープダンプを取得して MemoryAnalyzer で分析
- jmap -dump:format=b,file=<出力パス> -F <プロセスID>
(例) jmap -dump:format=b,file=/tmp/heap.dump -F 1001
-F は強制出力。-F を付けないとヒープダンプが取得できないことが多いが、-F なしで取得できるなら付けなくて良い。プロセスID>出力パス>
- https://www.eclipse.org/mat/ から Memory Analyzer (MAT) をダウンロードして読み込ませる。
(2024 追記)visualvm を使うのが良さそう。
ダウンロードして、<path>/bin/visualvm で起動。
https://visualvm.github.io/download.html
ヒープダンプに残っている文字列をカウントして多い順にソート
- strings -a java_pidxxx.hprof | sort | uniq -c | sort -nr | less
(参考) サイボウズエンジニアのブログ - Java トラブルシューティングガイド
ヒープ構成とコマンドライン指定
(1) | Eden | S0 | S1 | Old |
(2) | 64MB |
(3) | 1 | 2 |
(4) | 20MB |
(5) | 8 | 1 | 1 |
(1) 新しいオブジェクトは Eden に割り当てられる。その後 S0 と S1 を行ったり来たりして参照が残っている(解放されなかった)場合は Old に移動される。
(2) -Xmx: 64m: Eden + S0 + S1 + Old 合計で 64MB 割り当てる
(3) -XX:NewRatio=2: Eden + S0 + S1 合計の 2倍(1対2の比率)になるよう Old領域を割り当てる
(4) -XX:NewSize=20m: Eden + S0 + S1 が 20MB になるよう割り当てる
※NewRatio か NewSize のどちらか一方を指定する(両方は指定しない)。
(5) -XX:SurvivorRatio=8: Eden : S0 : S1 の比率が 8:1:1 になるよう割り当てる
(参考) Java8のHotSpotVMからPermanent領域が消えた理由とその影響