t

メモ

How to Examine Memory Usage of JVM

JVM の、主にメモリ消費の様子を知りたい。方法をいくつか調べたのでメモしておく。

今のところ次のような使い分けになりそう。

  • その場で様子を見るなら VisualVM
  • ログを取っておいて後から見るなら GCViewer
  • 何がどのくらいメモリを消費しているか調べるなら Eclipse Memory Analyzer

jmap

JDK 付属の jmap を jmap -heap <pid> のように実行すると JVM の各メモリ領域の使用量が分かる。

jcmd

JDK 付属の jcmd を jcmd <pid> GC.class_histogram のように実行すると、どのクラスのインスタンスがどのくらいメモリを使っているのかが分かる。ただし #bytes に各インスタンスが参照している先は含まれていない(あるクラス Klass が巨大な java.lang.String を参照していたとしても、それは Klass#bytes には反映されない)ようなので、解釈には注意が必要と思われる。

jstat

JDK 付属の jstat を jstat -gc <pid> のように実行してガベージコレクトされたヒープの統計データ を見たり jstat -gccause <pid> のように実行して直前や現在のガベージコレクションの原因 を見たりできる。

jvmtop

jvmtop を使うと top を使うような感じで JVM の様子を見ることができる。たとえば GC に費された時間の割合やヒープの使用量などが分かる。各数値の見方はドキュメントに書いてある。

VisualVM

VisualVM を使うと GUIJVM の様子を見ることができる。グラフで表示してくれるので、時系列を見たいときは jvmtop より便利そう。

GCViewer

GCViewer を使うと GC のログをグラフで表示することができる。

GC のログは java のオプションに -Xloggc:ログのパス -XX:+PrintGCDetails -XX:+PrintGCDateStamps あたりを指定して取れば良い。

Eclipse Memory Analyzer

Eclipse Memory Analyzer を使うと GUI でヒープダンプを解析できる。とくに dominator_tree を見ると何にメモリを取られているかが分かりやすい。

ヒープダンプは JDK 付属の jcmd で jcmd <pid> GC.heap_dump /path/to/dump.hprof のようにして取れる。あるいは java の起動オプションで -XX:+HeapDumpBeforeFullGC-XX:+HeapDumpAfterFullGC をつけるとフル GC の直前や直後にヒープダンプを取れる。ファイルはカレントディレクトリに java_pidNNNNN.hprof という名前(NNNNN は pid)で作られるらしい。複数作られるときは java_pidNNNNN.hprof, java_pidNNNNN.hprof.1, java_pidNNNNN.hprof.2 のように連番になる。

ところで Eclipse Memory Analyzer 自体の起動オプションには -Xmx1024m が指定されており(OS X の場合 MemoryAnalyzer.app/Contents/MacOS/MemoryAnalyzer.ini にある)少ないので、巨大なヒープダンプを解析したい場合は適当に増やした方が良い。