/home/by-natures/dev*

データ界隈で働くエンジニアとしての技術的なメモと、たまに普通の日記。

MemoryAnalyzer で巨大なヒープダンプファイルを扱う

ヒープダンプを扱った際のメモです。

メモリを多く使うアプリケーションが OOM エラーで落ちる際に、ヒープダンプを出力すると後々に調査が可能だと知りました。アプリケーション起動時に XX:+HeapDumpOnOutOfMemoryError オプションを設定するか、JMX 経由でアプリケーション実行中に設定することも可能です。アプリケーションが終了する際にのみ寄与するので、実行時のオーバーヘッドはなく、OOM エラーが発生しうるアプリケーションにとっては有用だと書かれています:

docs.oracle.com

hprof は J2SE 時代からある、ヒープ領域・CPU のプロファイリングツールとのこと。ヒープダンプを取るだけではないんですね。

OOM が発生すると、.hprof 拡張子のついたファイルがワーキングディレクトリに出力されます。OOM 時のヒープダンプなのでファイルサイズが非常に大きく、今回出てきたのが7GBほどのバイナリファイルでした。インターネット上では数十GBものヒープダンプをどうやって扱ったら良いのかの Q&A がありました。

Memory Analyzer

ヒープダンプを扱うツールに、Eclipse プラグイン(とスタンドアロン版もある)Memory Analyzer があります。Memory Analyzer を起動するためのヒープ領域がデフォルトでは小さめなので、MemoryAnalyzer.ini を開いてヒープ領域の最大値を広げておかないと、Memory Analyer 自信がヒープダンプファイルを読み込んだ時に OOM を発生させてしまいますので注意が必要です。

Memory Analyzer をコマンドラインで扱う

Memory Analyzer を起動すると GUI が現れ、インタラクティブにヒープダンプを解析できます。しかしヒープダンプファイル自体が大きい場合、この GUI で消費するメモリすら削減したい場合には、付属する ParseHeapDump.sh というコマンドがあります。

MemoryAnalyzer/FAQ - Eclipsepedia

javaforu.blogspot.jp

ParseHeapDump.shLinux 版の Memory Analyzer にしか付いていませんが、中身は Memory Analyzer の起動スクリプト-consoleLog オプションをつけているだけでした:

"$(dirname -- "$0")"/MemoryAnalyzer -consolelog -application org.eclipse.mat.api.parse "$@"

これを真似て、Mac OSコマンドラインで実行したところ、正常に動作しました:

cd mat.app/Contents/MacOS/
./MemoryAnalyzer -consoleLog -application org.eclipse.mat.api.parse <hprof ファイル>

これを実行すると、指定したファイルと同階層に .index ファイルが大量に生成されます。.index ファイルが生成されたあとであれば、GUI 経由でヒープダンプをインタラクティブに眺めることができます。

コマンドラインでもヒープダンプファイルに応じてメモリを大量に消費しますが、この .index ファイルさえあれば概ねのデータは GUI で確認できるので、メモリを多く積んだマシンで上記コマンドで .index ファイルを生成しておけばよい…とどこかの Q&A に書いてありました。ちょっと怖いですが、適当な作業用サーバ上で .index を作って、手元に落として GUI で分析…といった流れなのでしょうか(なかなか面倒ですね…)。

アプリケーション実行中に JMX からヒープダンプを取得

OOM 時ではなく、アプリケーション実行中にヒープダンプを取得するのに JMX が使えます。

http://blog.bosch-si.com/categories/technology/2011/11/how-to-get-a-heap-dump-of-a-remote-machine-via-jmx/