| まず前半では、HPが提供するプロファイリング・ツールHPjmeterを利用したメモリ・リーク解析の方法を解説します。
前回説明したとおり、Javaオブジェクトが必要とするメモリ領域は、JVMのヒープ・メモリから自動的に割り当てられます。また、不要になった(どこからも参照されなくなった)Javaオブジェクトはガベージ・コレクションによって収集され、そのメモリ領域は自動的に解放されます。よって、メモリ領域の確保や解放をプログラマが意識する必要がありません。そのため、Javaでは、CやC++のようなにメモリ・リークが多発することはなくなりました。
しかし、Javaにおいても、メモリ・リークが完全になくなったわけではありません。たとえば、JavaオブジェクトAのオブジェクト変数fooが、JavaオブジェクトBを参照しているケースを考えます。この場合、たとえBがプログラムの処理上は不要になったとしても、fooからBへの参照が存在するかぎり、Bはガベージ・コレクションの対象とはなりません。このように、プログラマが予想しないところでオブジェクトの参照が残ってしまうことを、「メモリ・リテンション」と呼びます。とくに、コレクションや配列を参照元とするメモリ・リテンションが多発すると、解放されないJavaオブジェクトが継続的に増加し、メモリ・リーク状態に陥ります。
メモリ・リーク解析の1つの方法として、ガベージ・コレクションを強制実行したあとにプログラムを終了させる方法があります。これを実施するには、プログラムを終了させる部分で以下のように記述します。
System.gc()
System.runFinalization()
System.gc()
System.exit() |
このとき、HP-JVMの起動のオプションには「-Xrunhprof:heap=all,cutoff=0」を追加しておきます。これにより出力されるプロファイル・データをHPjmeterで解析すれば、プログラムが終了した時点で残存するオブジェクトの状態を観察できます。
また、この方法を使えば、一定期間中の残存オブジェクトの増減を知ることも可能です。たとえば、プログラムが1時間動作する際に残存するオブジェクトを観察したいとします。そのためには、プログラムを2回実行し、2回目は1回目より1時間長く動作させます。そして、HPjmeterのCompare機能を利用して、得られた2つのプロファイル・データを比較します。
ここでは、プログラムを1時間実行したときと、2時間実行したときの、それぞれのプロファイル・データをHPjmeterでオープンします。具体的には、以下のメニュー操作を実施します。
- [File]→[Open]を選択し、2つのファイルを続けて開きます
- [File]→[Compare]を選択すると、2つのデータの概要が表示されます
- [Metric]→[Residual Objects(Count)]を選択します
以上の操作を行うと、以下の画面が表示されます。
 |
 |
| 図1:HPjmeterのCompare機能による比較 |
図1の比較結果を見ると、1時間目から2時間目の間に、Authorizeオブジェクトが8017個も増加していることがわかり、メモリ・リークの発生が疑われます。そこで、このAuthorizeオブジェクトをさらに詳しく解析してみます。まずは、あとで検索しやすくするため、同オブジェクトの行をマークしておきます。
- Authorizeオブジェクトの行をクリックし、[Edit]→[Mark to Find]を選択してマークします
|