トラブル解析方法
問題が発生した場合、以下の順に調査すると効率的かも。
- OSのCPU/メモリリソース確認
→ ボトルネックとなっているか確認 - GCログ解析
→ GCが多発していないか?ヒープ空きは十分か? - 違う場合、CPU使用率を確認
- CPU使用率が高い場合
→ メソッドプロファイリング - CPU使用率が高くない場合
→ スレッドダンプ解析 → ロック待ちでWaitしていないか?
ロック待ちの対象は何か?スレッドプール、コネクションプール辺りが多い。
プール初期値・最大値・使い方に問題がないか確認。
- CPU使用率が高い場合
※ 通常JavaアプリでCPU使用率が高いことで問題になることは稀。
だいたいDBが遅い(SQLチューニング、DBロック待ち)
http://www.atmarkit.co.jp/fjava/rensai4/troublehacks01/troublehacks01_3.html
VisualVM
プロファイルをする場合は VisualVM が便利
取得できるもの
CPU使用率グラフ
GC状況
ヒープ使用率グラフ(New/Eden/Old/Perm別も)
スレッドダンプ
ヒープダンプ
スレッドの状況グラフ(スレッド数の時系列グラフ、個別スレッドごとの稼動状態時系列グラフ)
CPUホットスポット(CPU使用時間の多いメソッド・クラスの確認、それらの呼び出し箇所の確認)
スレッド別のホットスポット
ヒープ内容の確認(ローカル接続のみ)
ヒープダンプの差分からメモリリークオブジェクトの確認、呼び出し箇所の確認
解析手順
- 事前にアプリのJava起動オプションにJMX指定をしておく。
- 対象プログラムを起動。
- $JAVA_HOME/bin/jvisualvm.exeを起動。
- 左ツリーのリモートを右クリックから追加で、接続先ホストを指定。
- 追加したホストをさらに右クリックからJMX接続を追加。ポート番号に1で指定したJMXポートを指定。
- ダブルクリックで接続開始。
これだけでCPU使用率・ヒープ使用量・スレッド状態のグラフ監視が可能。 - さらに「サンプラ」タブの「CPU」ボタンを押し、サンプリング開始させる。
ヒープを解析したい場合は「メモリ」ボタンを。(ただしリモートでヒープ詳細は確認不可) - 性能確認したい事象を発生させる。
- 事象が終わったところでサンプリングを終了させる。
- 必要に応じて事象前後等でスナップショットを取ると良い。
CPUサンプルではデフォルトで「セルフタイム」が選択されているが、これはThread.sleep()等の
時間も含まれるため、除外したい場合は「セルフタイム(CPU)」を選択すると良い。
その他解析ツール
- GCログ
- GCViewer
http://www.tagtraum.com/gcviewer.html
- スレッドダンプ
- Samurai
VisualVMでも可能
- ヒープダンプ
- MemoryAnalyzer(Eclipseプラグイン)
など
hprof:直接Windowsからネットワーク経由でプロファイラが使えない場合用
使えるならVisualVMを使ったほうが良い。
http://itpro.nikkeibp.co.jp/article/COLUMN/20061102/252525/
java -agentlib:hprof 実行クラス
で実行。結果は java.hprof.txt に出力される。
引数
デフォルトではヒープ情報のみ。
CPU利用率の高いものを取るには
-agentlib:hprof=cpu=samples
※ cpu=timesの方が正確になると思われるが、非常に遅いためsamplesを使う
jhat等のほかプログラムで開く場合には以下のようにバイナリフォーマットを指定する
-agentlib:hprof=format=b
- 詳細オプション
オプション 機能 デフォルト値 heap=dump/sites/all ヒープのプロファイリングを行う。 all cpu=samples/times/old CPU 時間のプロファイリングを行う。 off monitor=y/n モニターの競合のプロファイリングを行う。 n format=a/b 出力形式。aはASCII形式、bはバイナリ形式。 a file=name データを出力するファイル名を指定する。 java.hprof (ASCII の場合は .txt) net=host:port 指定した場合、プロファイリングデータをソケット経由で送信する。 ファイル出力 depth=size 出力スタックトレースの深さ。 4 cutoff=value 出力のカットオフポイント。
例えば0.2と指定した場合、ヒープ占有率または
CPU占有率が20%未満のデータは出力されない。0.0001 lineno=y/n トレースに行番号を出力するか。 y thread=y/n トレースにスレッド番号を出力するか。 n doe=y/n 終了時にダンプするかを指定する。 y
- 取得結果
rank CPU時間の順位 self CPU時間のパーセンテージ accum CPU使用時間の累積パーセンテージ(上位rankのselfとの和) count ヒットしたサンプリングタイミング数(samples指定)、またはメソッドのコール回数(times指定) trace 対応するトレース番号