Javaヒープダンプをキャプチャするさまざまな方法
1前書き
この記事では、Javaでヒープ・ダンプをキャプチャーするさまざまな方法を紹介します。
-
ヒープダンプは、ある瞬間にJVMのメモリ内にあるすべてのオブジェクトのスナップショットです。これらは、メモリリークの問題のトラブルシューティングやJavaアプリケーションのメモリ使用量の最適化に非常に役立ちます。
-
通常、ヒープダンプはバイナリ形式のhprofファイルに格納されています** jhatやJVisualVMなどのツールを使用してこれらのファイルを開いて分析できます。また、Eclipseユーザーにとっては、http://www.eclipse.org/mat/[MAT]を使用するのが一般的です。
次のセクションでは、ヒープダンプを生成するための複数のツールとアプローチについて説明し、それらの主な違いについて説明します。
2 JDKツール
JDKには、ヒープダンプをさまざまな方法でキャプチャするためのツールがいくつか付属しています。 ** これらのツールはすべて、JDKホームディレクトリ内の
bin
フォルダの下にあります。したがって、このディレクトリがシステムパスに含まれている限り、コマンドラインから起動できます。
次のセクションでは、ヒープダンプを取得するためにこれらのツールを使用する方法を示します。
2.1. jmap
jmapは実行中のJVMのメモリに関する統計情報を印刷するためのツールです。ローカルまたはリモートプロセスにそれを使用することができます。
-
jmapを使ってヒープダンプをキャプチャするには、
dump
オプションを使う必要があります。
jmap -dump:[live],format=b,file=<file-path> <pid>
そのオプションとともに、いくつかのパラメータを指定する必要があります。
-
live
:設定されている場合、アクティブな参照を持つオブジェクトのみを印刷します。
ガベージコレクションの準備ができているものは破棄します。このパラメータ
オプションです
**
format = b
:ダンプファイルをバイナリ形式にすることを指定します。もし
設定しない結果は同じです
**
file
:ダンプが書き込まれるファイル
-
pid
:JavaプロセスのID
例は次のようになります。
jmap -dump:live,format=b,file=/tmp/dump.hprof 12587
jps
コマンドを使用すると、Javaプロセスの
pid
を簡単に取得できることを忘れないでください。
-
jmapは実験的なツールとしてJDKに導入されており、サポートされていないことに注意してください。したがって、場合によっては、代わりに他のツールを使用することをお勧めします。
2.2. jcmd
jcmdは、JVMにコマンド要求を送信することによって機能する、非常に完成度の高いツールです。 Javaプロセスが実行されているのと同じマシンで使用する必要があります。
-
その多くのコマンドのうちの1つは
_GC.heap
dump
_
** です。プロセスの
pid__と出力ファイルのパスを指定するだけで、ヒープダンプを取得できます。
jcmd <pid> GC.heap__dump <file-path>
以前に使用したのと同じパラメータを使用して実行できます。
jcmd 12587 GC.heap__dump/tmp/dump.hprof
jmapと同様に、生成されるダンプはバイナリ形式です。
2.3. JVisualVM
-
JVisualVMは、Javaアプリケーションの監視、トラブルシューティング、プロファイル作成を可能にするグラフィカルユーザーインタフェースを備えたツールです。 GUIはシンプルですが非常に直感的で使いやすいです。
その多くのオプションのうちの1つは私達がヒープダンプを捕獲することを可能にします。 Javaプロセスを右クリックして
“ Heap Dump”
オプションを選択すると、ツールはヒープダンプを作成し、それを新しいタブで開きます。
“基本情報”
セクションに作成されたファイルのパスが見つかります。
3ヒープダンプを自動的に取得する
前のセクションで示したすべてのツールは、特定の時間に手動でヒープダンプを取得することを目的としています。場合によっては、
java.lang.OutOfMemoryError
が発生したときにヒープダンプを取得したいので、エラーの調査に役立ちます。
これらの場合、** Javaは
java.lang.OutOfMemoryError
がスローされたときにヒープダンプを生成する
HeapDumpOnOutOfMemoryError
コマンドラインオプションを提供します。
java -XX:+HeapDumpOnOutOfMemoryError
-
デフォルトでは、ダンプはアプリケーションを実行しているディレクトリの
java
pid <pid> .hprof
ファイルに保存されます。別のファイルまたはディレクトリを指定したい場合は、
HeapDumpPath__オプションでそれを設定できます。
java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=<file-or-dir-path>
このオプションを使用してアプリケーションのメモリが不足すると、ログにヒープダンプを含む作成ファイルが表示されます。
java.lang.OutOfMemoryError: Requested array size exceeds VM limit
Dumping heap to java__pid12587.hprof ...
Exception in thread "main" Heap dump file created[4744371 bytes in 0.029 secs]java.lang.OutOfMemoryError: Requested array size exceeds VM limit
at com.baeldung.heapdump.App.main(App.java:7)
上記の例では、
java
pid12587.hprof__ファイルに書き込まれています。
ご覧のとおり、このオプションは非常に便利であり、
このオプションを指定してアプリケーションを実行してもオーバーヘッドはありません。したがって、特に本番環境では、このオプションを常に使用することを強くお勧めします。
最後に、** このオプションは
HotSpotDiagnostic
MBeanを使用して実行時に指定することもできます。そのためには、JConsoleを使用して
HeapDumpOnOutOfMemoryError
VMオプションを
true
に設定します。
リンク:/uploads/jconsole-setvmoption-1-100×84.png%20100w[]
私達はこのhttps://www.baeldung.com/java-management-extensions[article]にMBeanとJMXに関するより多くの情報を見つけることができます。
4 JMX
この記事で取り上げる最後のアプローチはJMXを使用することです。
前のセクションで簡単に紹介した
HotSpotDiagnostic
MBean
を使用します。 ** このMBeanは2つのパラメータを受け取る
dumpHeap
メソッドを提供します。
-
outputFile
:ダンプ用のファイルのパス。ファイルは
hprof拡張子
**
live
:trueに設定すると、メモリ内のアクティブなオブジェクトだけをダンプします。
以前にjmapで見たことがある
次のセクションでは、ヒープダンプを取得するためにこのメソッドを呼び出す2つの異なる方法を示します。
4.1.
JConsole
HotSpotDiagnostic
MBeanを使用する最も簡単な方法は、JConsoleなどのJMXクライアントを使用することです。
JConsole
を開いて実行中のJavaプロセスに接続すると、
MBeans
タブに移動して
__
com.sun.management
の下の
HotSpotDiagnostic
が見つかります。
オペレーションでは、前に説明した
dumpHeap__メソッドを見つけることができます。
リンク:/uploads/jconsole-dump-1-100×84.png%20100w[]
図に示すように、
dumpHeap
操作を実行するには、
outputFile
および
live
の各パラメーターを
p0
および
p1
テキストフィールドに追加するだけです。
4.2. プログラムによる方法
HotSpotDiagnostic
MBeanを使用するもう1つの方法は、Javaコードからプログラムで呼び出すことです。
そのためには、まずアプリケーションに登録されているMBeanを取得するために
MBeanServer
インスタンスを取得する必要があります。その後、**
HotSpotDiagnosticMXBean
のインスタンスを取得し、その
dumpHeap
メソッドを呼び出すだけです。
コードで見てみましょう。
public static void dumpHeap(String filePath, boolean live) throws IOException {
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
HotSpotDiagnosticMXBean mxBean = ManagementFactory.newPlatformMXBeanProxy(
server, "com.sun.management:type=HotSpotDiagnostic", HotSpotDiagnosticMXBean.class);
mxBean.dumpHeap(filePath, live);
}
-
hprofファイルは上書きできないことに注意してください。** したがって、ヒープダンプを出力するアプリケーションを作成するときには、これを考慮する必要があります。そうしないと、例外が発生します。
Exception in thread "main" java.io.IOException: File exists
at sun.management.HotSpotDiagnostic.dumpHeap0(Native Method)
at sun.management.HotSpotDiagnostic.dumpHeap(HotSpotDiagnostic.java:60)
5結論
このチュートリアルでは、Javaでヒープダンプをキャプチャする方法をいくつか示しました。
経験則として、Javaアプリケーションを実行するときは常に
HeapDumpOnOutOfMemoryError
オプションを使用するようにしてください。他の目的のために、私たちがjmapのサポートされていないステータスを覚えている限り、他のツールのどれでも完璧に使うことができます。
いつものように、例の完全なソースコードはhttps://github.com/eugenp/tutorials/tree/master/core-java[GitHubで利用可能]です。