Edited at

Java開発の性能改善! その3 ヒープダンプを取ろう

More than 3 years have passed since last update.

第3回になります。

記事を書くこと自体に時間がかかってしまうので

見やすい記事にするってのが難しいですね。。

少しずつ改良していきます。

ストックやフォローをして頂けると励みになります。

 

さて、本題です。

jstatやGCログなどを見てメモリがなかなか開放されない場合は

ヒープダンプを取ってメモリの中身を解析することになります。


ヒープダンプの取得

まず、jstatやpsコマンド等で対象のJVMのプロセスIDを取得しましょう。


jps -v | less -SN

プロセスIDがわかったらjmapコマンドでダンプを取ります。

サーバのディスク容量に注意してください。

heapサイズを2GBとかに設定した場合は2GB以上のファイルが

生成されることがあります。


jmap -dump:format=b,file=./heapdump.hprof {プロセスID}

これで指定した場所にダンプファイルができます。

-dump:live,format=...というようにliveをつけるとGCが起きて

コマンド実行時に活きているオブジェクトのみのダンプになるようです。

とりあえず今回はフルで取ります。


ヒープダンプの中身を解析をする

解析をするにはツールを使います。

java標準のjhatやMemory Analyzer、HeapAnalyzerなど

いくつかありますが今回はMemory Analyzerを使います。

Eclipseベースなのでサイズの大きいダンプファイルを開く場合は

MemoryAnalyzer.iniの設定でツール自体のヒープサイズを

増やすようにしてください。

file->Open Heap Dumpより先ほど取得したファイルを指定して、

次に出てきたダイアログでLeak Suspects Reportを選択。

少し待つとoverviewが開くのでReportのLeak Suspectsをさらに選択しましょう。

image.png

そうするとツールがメモリリークの疑いがある場所を探してくれます。

※あくまで疑いなので、違う場合もあるし見つからないリークもある。

上記の図ではT4CPreparedStatementが5000弱のインスタンスを保持していて

25%の容量を使っていると教えてくれています。

Details >> というリンクを押すと対象オブジェクトを持つ上位参照を教えてくれます。

image (1).png

どうやら50個のTxConnectionListenerの配下に約100個ずつT4CPreparedStatementを保持していて

5000個弱(4953個)のT4CPreparedStatementを持っている様子。

TxConnectionListenerが直接T4CPreparedStatementを持っているわけではないようで

このビューではここまでしか見れないようなので

Dominator TreeからT4CPreparedStatementを検索して参照元を深堀しましょう。

image (2).png

中身はSQL情報のキャッシュなどでした。まぁ、PrepareStatementですからね。

ではこれの参照元を辿りましょう。

T4CPreparedStatementをクリックしてPath To GC Roots->with all referencesを選択すると

参照元を追っていけます。

image (4).png

階層を見ていくとcache(PreparedStatementCache)が保持しているということがわかります。

ここまでの情報をからコネクション(TxConnectionListener)が50個あってそれらが

キャッシュ(PreparedStatementCache)を100個持っているということがわかったので

DB(データソース)の接続設定がこの通りなのかサーバ設定を確認しましょう。

image (5).png

ConnectionPool Sizeが50、 Statement Cache Sizeが100でした。

仮説は当たっているようですね。どう見ても多すぎです。はい。

適切値に直してヒープダンプを取り直したところメモリの使用率も大幅に削減できました。

今回はミドルウェア設定が起因でしたが

開発したアプリケーション起因のリークが疑わしい場合は

サーバ起動時、数分後、数時間後などDumpを何度も取って確認しましょう。

2つのヒープダンプの差分を取る機能もあるので残り続けている(リークしている)オブジェクトはないか・・・

異様に大きいサイズのオブジェクトはないか・・・などをチェックしていきます。

今日はここまで!