Javaヒープダンプをキャプチャするさまざまな方法

Javaヒープダンプをキャプチャするさまざまな方法

1. 前書き

この記事では、Javaでヒープダンプをキャプチャするさまざまな方法を紹介します。

A heap dump is a snapshot of all the objects that are in memory in the JVM at a certain moment。 メモリリークの問題をトラブルシューティングし、Javaアプリケーションのメモリ使用量を最適化するのに非常に役立ちます。

Heap dumps are usually stored in binary format hprof files. jhatやJVisualVMなどのツールを使用して、これらのファイルを開いて分析できます。 また、Eclipseユーザーの場合、MATを使用するのが非常に一般的です。

次のセクションでは、ヒープダンプを生成するための複数のツールとアプローチについて説明し、それらの主な違いを示します。

2. JDKツール

JDKには、さまざまな方法でヒープダンプをキャプチャするためのいくつかのツールが付属しています。 All these tools are located under the bin folder inside the JDK home directory。 したがって、このディレクトリがシステムパスに含まれている限り、コマンドラインから起動できます。

次のセクションでは、ヒープダンプをキャプチャするためにこれらのツールを使用する方法を示します。

2.1. jmap

jmapは、実行中のJVMのメモリに関する統計情報を出力するツールです。 ローカルプロセスまたはリモートプロセスに使用できます。

jmapを使用してヒープダ​​ンプをキャプチャするには、dumpオプションを使用する必要があります。

jmap -dump:[live],format=b,file= 

そのオプションとともに、いくつかのパラメーターを指定する必要があります。

  • live:設定すると、アクティブな参照を持つオブジェクトのみが表示され、ガベージコレクションの準備ができているオブジェクトは破棄される。 このパラメーターはオプションです

  • format=b:ダンプファイルがバイナリ形式になることを指定します。 設定されていない場合、結果は同じです

  • file:ダンプが書き込まれるファイル

  • pid:JavaプロセスのID

例は次のようになります。

jmap -dump:live,format=b,file=/tmp/dump.hprof 12587

jpsコマンドを使用すると、Javaプロセスのpidを簡単に取得できることに注意してください。

Keep in mind thatjmap was introduced in the JDK as an experimental tool and it’s unsupported.したがって、場合によっては、代わりに他のツールを使用する方が望ましい場合があります。

2.2. jcmd

jcmdは、JVMにコマンドリクエストを送信することで機能する非常に完全なツールです。 Javaプロセスが実行されているのと同じマシンで使用する必要があります。

One of its many commands is the GC.heap_dump。 プロセスのpidと出力ファイルのパスを指定するだけで、ヒープダンプを取得できます。

jcmd  GC.heap_dump 

以前に使用したのと同じパラメーターを使用して実行できます。

jcmd 12587 GC.heap_dump /tmp/dump.hprof

jmapと同様に、生成されるダンプはバイナリ形式です。

2.3. JVisualVM

JVisualVM is a tool with a graphical user interface that lets us monitor, troubleshoot and profile Java applications。 GUIはシンプルですが、非常に直感的で使いやすいです。

その多くのオプションの1つにより、ヒープダンプをキャプチャできます。 Javaプロセスを右クリックして、“Heap Dump”オプションを選択すると、ツールはヒープダンプを作成し、新しいタブで開きます。

image

“Basic Info”セクションで作成されたファイルのパスを見つけることができることに注意してください。

3. ヒープダンプを自動的にキャプチャする

前のセクションで示したすべてのツールは、特定の時間にヒープダンプを手動でキャプチャすることを目的としています。 場合によっては、java.lang.OutOfMemoryErrorが発生したときにヒープダンプを取得して、エラーの調査に役立てたいことがあります。

これらの場合、Java provides the HeapDumpOnOutOfMemoryError command-line option that generates a heap dump when a java.lang.OutOfMemoryError is thrown:

java -XX:+HeapDumpOnOutOfMemoryError

デフォルトでは、アプリケーションを実行しているディレクトリのjava_pid<pid>.hprofファイルにダンプが保存されます。 別のファイルまたはディレクトリを指定する場合は、HeapDumpPathオプションで設定できます。

java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=

このオプションを使用してアプリケーションのメモリが不足すると、ヒープダンプを含む作成されたファイルをログで確認できます。

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.example.heapdump.App.main(App.java:7)

上記の例では、java_pid12587.hprofファイルに書き込まれています。

ご覧のとおり、このオプションは非常に便利で、there is no overhead when running an application with this option. Therefore, it’s highly recommended to use this option always, especially in production.

最後に、this option can also be specified at runtime by using the HotSpotDiagnostic MBean。 これを行うには、JConsoleを使用して、HeapDumpOnOutOfMemoryError VMオプションをtrueに設定します。

image

MBeanとJMXの詳細については、このarticleを参照してください。

4. JMX

この記事で取り上げる最後のアプローチは、JMXを使用することです。 前のセクションで簡単に紹介したWe’ll use the HotSpotDiagnostic MBean。 2つのパラメータを受け入れるThis MBean provides a dumpHeap method

  • outputFile:ダンプ用のファイルのパス。 ファイルにはhprof拡張子が必要です

  • live:trueに設定すると、前のjmapで見たように、アクティブなオブジェクトのみがメモリにダンプされます。

次のセクションでは、ヒープダンプをキャプチャするためにこのメソッドを呼び出す2つの異なる方法を示します。

4.1. JConsole

HotSpotDiagnostic MBeanを使用する最も簡単な方法は、JConsoleなどのJMXクライアントを使用することです。

JConsoleを開いて、実行中のJavaプロセスwe can navigate to the MBeans tab and find the HotSpotDiagnostic under*com.sun.management*. In操作に接続すると、前に説明したdumpHeapメソッドを見つけることができます。

image

示されているように、dumpHeap操作を実行するには、パラメータoutputFileおよびlivep0およびp1テキストフィールドに導入する必要があります。

4.2. プログラマティックな方法

HotSpotDiagnostic MBeanを使用するもう1つの方法は、Javaコードからプログラムで呼び出すことです。

そのためには、アプリケーションに登録されているMBeanを取得するために、最初にMBeanServerインスタンスを取得する必要があります。 その後、we simply need to get an instance of a HotSpotDiagnosticMXBean and call its dumpHeap method

コードで見てみましょう:

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);
}

Notice that an hprof file cannot be overwritten.したがって、ヒープダンプを出力するアプリケーションを作成するときは、これを考慮に入れる必要があります。 そうしないと、例外が発生します。

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のサポートされていない状態を念頭に置いている限り、他のツールは完全に使用できます。

いつものように、例の完全なソースコードはover on GitHubで入手できます。