2-3-2:オブジェクトの参照を調べる


・ Javaのプログラム内ではオブジェクトに対応する変数が宣言されます。 ただし、こうした変数はオブジェクトの実体そのものではありませんでした。 より正確に言えば「オブジェクトへの参照」です。 したがって変数の指し示すオブジェクトは常に同じものであるとは限りません。 あるいは次のような例のようにプログラムの処理が進むにつれて、 オブジェクトを参照する変数の個数も変化していきます。


   Color color1 = new Color( 200, 100, 200 );
   Color color2 = color1;   // 2個の変数が共通のオブジェクトを参照
   color1 = null;           // color1 の参照を消去
   color2 = null;           // color2 の参照も消去

オブジェクトに対する参照の個数は、 nullの代入やブロックを抜けて変数の寿命が尽きたりすることで減少していきます。 そして変数による参照の個数が完全に0になった時点で、 「オブジェクトは不用になった」と判断されるわけです。
 ただし参照の個数が0になったことを、GCが即座に判定するわけではありません。 実際には多少の時間のズレが存在します。 したがってオブジェクトの生成から消滅までの間に以下の3段階があることになります。

  1. オブジェクトへの参照が少なくとも1個はある状態。 この期間は GCによってオブジェクトの実体が消去されることはありません。
  2. オブジェクトへの参照は1個もないが、GCが消去の処理を実行していない状態。 プログラムから参照されることはありませんが、 オブジェクトの実体はまだメモリ上に存在しています。
  3. GCの処理によってオブジェクトの実体がメモリ上から消去された状態。

 さて、 オブジェクトの参照の状態をコントロールするサンプルを紹介しようと思いますが、 この種のプログラムには本質的に困難がついてまわります。 オブジェクトの状態を調べるためには、 当然その対象のオブジェクトを参照しなくてはいけません。 「オブジェクトが参照をされているか、されていないか?」 を調べるにはどうしたらいいのでしょうか?  あるいは、「参照がなくなったオブジェクトが GCの処理の対象となったか?」 を知る方法があるのでしょうか?
 このジレンマを解決する機構として JDK1.2 から新しいパッケージ java.lang.ref が追加されました。 java.lang.ref という名前は、java.lang.reflect と 紛らわしいのですが、"ref" は "Reference(参照)" の意味です。 パッケージの中心になるのは Referenceという名前の抽象クラスとそのサブクラスです。
 Referenceのオブジェクトは、通常の変数と同じように 他のオブジェクトへの参照を行うことができます。 参照の対象のオブジェクトはメソッド set(),get()によって取り扱われます。 Reference自身は抽象クラスで、 実際のプログラム内では目的に応じて Referenceのサブクラスのいずれかが用いられます。 WeakReference もそうしたサブクラスの1つです。 WeakReferenceによる参照はシステムの GCの処理に影響を与えません。 WeakReferenceによって参照されていても、 それ以外の参照がなくなった時点でオブジェクトは GCの対象となります。 したがって参照がなくなった後のオブジェクトの状態を追跡して「観察する」 ことが可能です。 WeakReferenceを利用したサンプル WeakRefTest.javaを紹介しましょう。
 ここでは試しに Colorのオブジェクトを1個生成し、 それを参照する WeakReferenceのオブジェクトも1個用意します。 プログラム内の step1, step2, step3が、 先に説明した3つの段階に対応していることを確認してください。 step1 では通常の変数 ivory によるオブジェクトの参照が存在します。 step2 では ivoryに null が代入され、Colorのオブジェクトへの参照が なくなります。ただし、一般にはこの直後にオブジェクトが消滅するわけでは ありません。GCの対象となるまではオブジェクトの実体は残されているはずです。 step3 で GCの処理が行われるとオブジェクトは完全に消滅します。 GCを強制的に実行させるためには Systemクラスの gc()メソッドを呼び出します。 プログラムと実行してみて、参照がなくなったオブジェクトの実体が、 どのような状態にあるかを確認してみてください。

・ Referenceの他のサブクラスである SoftReference を利用すると、 特定のオブジェクトのメモリ管理を GCの機構とは独立に管理することも可能です。 SoftReferenceが参照しているオブジェクトは プログラム内の変数による参照の有無に影響を受けません。 明示的にメモリを解放するまで存在し続けます。 たとえば巨大なテーブルのオブジェクトのように、生成のために大きな負荷が 生じ、なおかつ何度も繰り返し呼び出される可能性があるオブジェクトの場合には、 GCの機構とは別に管理した方が効率が良い場合もあります。 ただし、その場合には当然アプリケーションの側でメモリの解放に関して 責任を負わなくてはいけません。
 SoftReferenceによってアプリケーションが独自にメモリの確保と解放を 行なうサンプル MemoryCheck.java を紹介しましょう。 Runtimeクラスの totalMemory(),freeMemory()メソッドでマシンの メモリ使用の状況を調べます。 そしてメモリの使用状況が切迫した状況になったら、 生成していた余分な配列のデータを解放します。