Effective Java 第 2 版:第 2 章 オブジェクトの生成と消滅 項目 6

廃れたオブジェクト参照を取り除く

自前でメモリ管理しているときは、廃れた参照が現れてメモリリークを起きることを防がなければならないという話。

廃れた参照とは、存在しているが使われることのない参照のことである。 例えば、配列を用いてオブジェクトを格納するスタックを自前で管理しているとする。 このとき、以下のようなコードだと、ポップされた要素は誰も使わない参照となってしまう(意図しないオブジェクト保持)。 これが廃れた参照である。

public Object pop() {
    Object ret = stack[--size];    // stack[size] が廃れた参照になる
    return ret;
}

廃れた参照が指すオブジェクトは、参照自体は残っているため、JVM のガベージコレクション (GC) で回収されない。 つまり、メモリリークになりうる。 廃れた参照を防ぐために、以下の方法が挙げられている。

  • 使わなくなった参照には null を代入する
  • 弱い参照を使う

使わなくなった参照には null を代入する

スタックから要素をポップしたあとは、ポップした要素が入っていた場所に null を代入しなければならない。

public Object pop() {
    Object ret = stack[--size];
    stack[size] = null;    // 廃れた参照を防ぐ
    return ret;
}

一方で、基本的には、参照変数のスコープをできるだけ局所化して、すぐにスコープ外に出すようにする方針の方がよいとのこと。

弱い参照を使う

弱い参照とは、ある参照のみがあるオブジェクトを指している状態になったとき、そのオブジェクトがガベージコレクションの回収対象となるような参照のことである。 WeakHashMap は、エントリのキーが弱い参照で保持されており、そのキーが外部から参照されなくなると、GC の対象となる。

自前でキャッシュを作っていると、キャッシュしたこと自体を忘れてしまい、廃れた参照が残り続けることがある。 キャッシュを WeakHashMap で実装することで、廃れた参照を防ぐことができる。

何らかの API に対するリスナーやコールバックの登録時にも、そのコールバックなどが自動で登録解除されない場合は、廃れた参照となって残り続ける。 これも、弱い参照を使えば防ぐことができる。

参考文献

EFFECTIVE JAVA 第2版 (The Java Series)

EFFECTIVE JAVA 第2版 (The Java Series)