2010年5月1日土曜日

Effective javaまとめ5 廃れたオブジェクト参照を取り除く1

京都は良い。

--------------------------------------------------
■項目5 廃れたオブジェクト参照を取り除く

javaはガーベジコレクションを持つ言語であるため、メモリ管理は意識しなくなりがちですが、それは問題があります。

例えば、スタック実装を持つ以下のクラスを見てください。

--------------------------------------------------

public class SampleStack () {

 private Object[] stack = new Object[] {};
 private int size = 0;

 public void push (Object obj) {
  stack[size++] = obj;
 }

 public Object pop () {
  return stack[--size];
 }

}
--------------------------------------------------

※sizeが0の時popすると落ちますが、例なので気にせずに・・。

このプログラムはメモリリークを抱えています。
どこが問題なのでしょうか。

・・・・。

stackが大きくなった後に小さくなっても、stack自身がそのオブジェクトに対する参照を保持し続ける、という点です。

例えば、pushが10回行われ、popが5回行われたとします。
このとき、stack[5] ~ stack[9]に格納されているオブジェクトは外部のプログラムからアクセスする方法はなくなります。しかし、stack自身は参照を保持し続けているため、これらのオブジェクトはガーベージコレクト対象となりません。

あるオブジェクト参照が保持され続けると、そのオブジェクトが参照しているオブジェクトも回収されず、更にその先も回収されません。

上記に対する解決方法は単純です。

参照が不要になった時点で、参照にnullを設定すれば問題ありません。

改善するとこんな感じです。
--------------------------------------------------
 public Object pop () {
stack [--size] = null;
  return stack[size];
 }
--------------------------------------------------

nullを設定する利点はもう1つあります。

もし使用する意図のない参照を誤って使用した場合、プログラムは間違った挙動をとらず、ヌルポが発生するため、プログラミングエラーを早めに発見するこができる、という点です。

しかし、nullを設定する、という対処方法をいつも採用すれば良いわけではありません。
なぜなら、上記対処はプログラムを不必要に複雑にし、パフォーマンスが低下することも考えられるからです。

最善の方法は、その参照が含まれていた変数を再利用するか、その変数のスコープの外に出ることです。

--> つづく

0 件のコメント:

コメントを投稿