CodeZine(コードジン)

特集ページ一覧

Javaファイナライズのメモリ保持問題への対処方法

JVMのファイナライズ処理の仕組みとテクニック

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2006/03/09 12:00

Javaのファイナライズ機能はオブジェクトの事後クリーンアップを可能にしますが、ファイナライズを明示的に使っていない場合でも、リソースの再生に遅延が生じることがあります。本稿では、このようなメモリ保持問題を回避する方法について説明します。

目次

はじめに

 Javaのファイナライズ機能は、ガベージコレクタが到達不能と判断したオブジェクトに対して事後クリーンアップを実行するための仕組みです。通常は、オブジェクトに関連付けられたネイティブリソースを再生(reclaim)する場合に使います。簡単なファイナライズの例を次に示します。

public class Image1 {
    // pointer to the native image data
    private int nativeImg;
    private Point pos;
    private Dimension dim;

    // it disposes of the native image;
    // successive calls to it will be ignored
    private native void disposeNative();
    public void dispose() { disposeNative(); }
    protected void finalize() { dispose(); }

    static private Image1 randomImg;
}

 Image1のインスタンスが到達不能になると、Java仮想マシン(JVM)は状況に応じて、画像データ(この例では整数型のnativeImgで参照)を保持しているネイティブリソースを確実に再生するためにImage1finalize()メソッドを呼び出します。ここで注意してほしいのは、finalize()メソッドはJVMによって特殊な扱いを受けるものの、任意のコードからなる任意のメソッドだという点です。具体的には、finalize()メソッドはオブジェクト内のすべてのフィールド(この例ではposdim)にアクセスできます。また、驚くべきことに、finalize()メソッドの中でオブジェクトを再び到達可能にすることもできます(たとえばrandomImg = this;として静的フィールドから到達可能にするなど)。このプログラミング手法はあまりお勧めしませんが、方法としては可能です。

 ここで、ファイナライズ可能なオブジェクト(クラスに有効なファイナライザが定義されているオブジェクト)が作成されてから回収されるまでの流れを見てみましょう。オブジェクトの名前はobjとします(図1を参照)。

図1 ファイナライズ可能なオブジェクトobj
図1 ファイナライズ可能なオブジェクトobj
  1. objが割り当てられるときに、JVMはobjがファイナライズ可能であることを内部に記録します(通常はこれによってJVMの高速割り当てパスの速度が低下します)。
  2. ガベージコレクタがobjを到達不能と判断します。このとき、ガベージコレクタは割り当て時の記録からobjがファイナライズ可能であることを認識し、このオブジェクトをJVMのファイナライズキューに追加します。また、その時点で到達不能になっているオブジェクトでも、それがobjから到達可能なオブジェクトであれば、ファイナライザからアクセスされる可能性があるのですべて保持します。図2に、Image1インスタンスの場合の例を示します。
  3. その後、JVMのファイナライザスレッドobjをキューから取り出し、objfinalize()メソッドを呼び出して、ファイナライザが呼び出されたことを記録します。この時点で、objは「ファイナライズ済み」と見なされます。
  4. ガベージコレクタが再びobjを到達不能と判断しますが、今度はファイナライズ済みなので、objのスペースと、objオブジェクトから到達可能なすべてのオブジェクト(ただし他から到達不能なもの)を回収します。
図2 ガベージコレクタがobjを到達不能と判断する
図2 ガベージコレクタがobjを到達不能と判断する

 ガベージコレクタがobjを回収するのに最低でも2サイクルを必要とし、このプロセス中はobjから到達可能なすべてのオブジェクトを保持する必要があることに注意してください。この点を忘れていると、一時的に予想外のリソース保持問題が発生する可能性があります。もう1つ注意してほしいのは、JVMは、割り当てられたすべてのファイナライズ可能なオブジェクトのファイナライザを呼び出すとは限らないという点です。ガベージコレクタが一部のオブジェクトを到達不能と見なす前にJVMが終了することもあります。


  • LINEで送る
  • このエントリーをはてなブックマークに追加

修正履歴

  • 2006/03/27 14:17 オブジェクトの「再生」という表記を、「回収」に修正しました(リソースの再生、JVMの再生処理などは、そのまま)。

あなたにオススメ

著者プロフィール

  • Tony Printezis(Tony Printezis)

    SunLabsでの3年以上の勤務を経て、Sun MicrosystemsのJava HotSpot Virtual Machine開発チームに参加。主に、ガベージコレクタのスケーラビリティ、反応性、並列性、ビジュアル化を中心に、動的メモリ管理に携わる。

  • japan.internet.com(ジャパンインターネットコム)

    japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.com や EarthWeb.c...

バックナンバー

連載:japan.internet.com翻訳記事

もっと読む

All contents copyright © 2005-2021 Shoeisha Co., Ltd. All rights reserved. ver.1.5