OutOfMemoryError を分析する

最近仕事で Java ばかりの KrdLab です.そんな中,Eclipse の Memory Analyzer (MAT) が素晴らしかったので紹介.
http://www.eclipse.org/mat/

はじめに

Java ではメモリリークによって OutOfMemoryError (OOME) が発生する.このリークを特定する作業はなかなか困難な作業になることが多い (特に,誰が作ったのかわからない古いコードの保守で発生すると大変!).
今回はその作業コストを軽減するツールとして Memory Analyzer (MAT) を紹介する.

Eclipse Memory Analyzer とは?

JVM のヒープダンプを解析するツール.どのオブジェクトがリーク候補なのか,どこから参照されていたものだったのか,といった情報がグラフィカルに表示される.
他にもダンプ分析のための様々な機能があり,非常に強力なツールである.

ヒープダンプを取得するには?

OutOfMemoryError 発生時に取得する場合
以下のように HeapDump* オプションを JVM に指定する.

>java -Xmx128m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./dump.hprof -cp ...

上記であれば,128 MB を超えたところでヒープダンプ dump.hprof が出力される.
参考:http://blogs.sun.com/watt/resource/jvm-options-list.html


任意のタイミングで取得する場合
jmap で取得する.(他にもいくつか方法があるけど割愛)

>jmap -dump:format=b,file=test.hprof 5624

これで PID=5624 のヒープダンプが test.hprof として出力される.
参考:jmap - Memory Map


ただしサーバ系 OS の場合,実行権限の関係上 jmap が正常に実行できない場合がある.そのような場合は PsTools の PsExec を使用すると良い."-s" オプションをつけることで,jmap を System アカウントで実行できる.

>PsExec.exe -s jmap -dump:format=b,file=test.hprof 5624

参考:PsExec | Microsoft Docs

Memory Analyzer を使ってみる

以下のようなシンプルなコードを用意した.あからさまなリークについてはあしからず.

package com.example.test.mat;
import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) throws Exception {
        final Thread th = new Thread(new Leaker(), "leak-thread");
        th.start();
        th.join();
    }
}

class Leaker implements Runnable {
    private final List<Integer[]> list = new ArrayList<Integer[]>();

    public void run() {
        for (int i = 0; i < 1024; ++i) {
            list.add(new Integer[1024 * 1024]);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException _ignore_) {
            }
        }
    }
}
// コンパイル:javac -d ./bin -cp ./src -encoding utf-8 src/com/example/test/mat/Main.java

前述した方法でヒープダンプを取得し,MAT で「Leak Suspects」を開く.

(※この円グラフで「ここヤバそう」というのがわかる)
「Details」リンクから詳細画面に移動すれば,個々のオブジェクトについて詳細な情報を得ることができる.

画面から,Leaker の ArrayList でリークしていることがわかる.実行スレッドの名前は "leak-thread" である.
各要素のリンクを選択することでさらに分析を進めていくことができる.

最後に

Eclipse Memory Analyzer はヒープダンプを分析するツールです.機能・操作性ともに素晴らしい.
実際に以下のようなことに使ってみて,とても便利でした.

  • OutOfMemoryError 発生箇所の特定と確認
  • メモリ使用量の推測値を検証

まぁ,機能は紹介しきれないため,実際にさわってみることをおすすめします.(^_^)