#廃れたオブジェクト参照を取り除く
C言語のようにメモリ管理を手動でする言語からすると、ガベージコレクタは魔法のようなものに見えるかもしれない。
しかしそれでもメモリリークを引き起こす原因は存在するから注意しようねって話。
##サンプルコード
//"メモリリーク"を発見できますか?
public class Stack {
private Object[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
public Stack() {
this.elements = new Object[DEFAULT_INITIAL_CAPACITY];
}
public void push(Object e) {
ensureCapacity();
elements[size++] = e
}
public Object pop() {
if (size == 0)
throw new EmptyStackException();
return elements[--size];
}
/**
* 配列を大きくする必要があるごとに要領をだいたい倍にして、
* 最低もう一つの要素分の要領を確保する。
*/
private void ensureCapacity() {
if (elements.length == size)
elements = Array.copyOf(elements, 2 * size + 1);
}
}
public Object pop() {
if (size==0)
throw new EmptyStackException();
Object result = elements[--size];
elements[size] = null; //廃れた参照を取り除く
return result;
}
##メモリリークを引き起こす3つの原因
###1つ目 廃れた参照
例1は一見問題ないように見えますが廃れた参照を保持しています。
例2のようにいらなくなった参照にはnullを設定してあげることでメモリリークを防ぐことができます。
ですが、全ての使い終わったプログラムに対して過度にnullを設定する必要はありません。
Stackクラスは独自のメモリ管理をしています。
そのようなクラスのどの参照が不要なのか、ガベージコレクタは知ることができません。
nullを手作業で設定することによってガベージコレクタに無効な部分を効果的に教えてあげることができます。
###2つ目 キャッシュ
オブジェクト参照をいったんキャッシュへ入れてしまうと、オブジェクト参照がそこにあることを忘れがちですし、そのオブジェクト参照の意味がなくなったかなり後でもキャッシュに残したままにしがちです。キャッシュの外にあるエントリーのキーへの参照が存在するかぎりそのエントリーに意味があるキャッシュを実装するのであれば、そのキャッシュをWeakHashMapで表現するのが良い。
WeakHashMap:エントリーが廃れてしまうと自動的に取り除かれる
###3つ目 リスナーやコールバック
明示的に登録を解除しないAPIを実装すると、何らかの処理を行わなければコールバックが蓄積されてしまいます。迅速にコールバックがガベージコレクトされることを保証する最善の方法は、それらに対する弱い参照(weak reference)だけを保存することです。
#続く
【Effective Javaを読む】 第2章 項目7 『ファイナライザを避ける』
https://qiita.com/Natsukii/items/785ae41361cb7324e45b