『Effective java』読書ノート2——メモリリーク


JVMはゴミ回収器を提供しており、javaプログラマーはC/C++プログラマーのように一日中オブジェクトのクリーンアップ作業に頭を悩ませる必要はありませんが、Javaではメモリ漏れがないわけではありません.典型的なメモリオーバーフローの例を示します.
下位データ構造として配列を使用してStackスタックデータ構造を実現するコンテナです.コードは次のとおりです.
public class Stack{
	private Object[] elements;
	private int size = 0;
	private static final int DEFAULT_SIZE = 15;
	public Stack(){
	elements = new Object[DEFAULT_SIZE];
}
public void push(Object o){
	ensureCapatity();
	elements[size++] = o;
}
public Object pop(){
	if(size == 0){
	throw new EmptyStackException();
}
return elements[--size];
}
//     ,        
public ensureCapatity(){
	if(elements.length == size){
	elements = Arrays.copyOf(elements, 2 * size + 1);
}
}
}

どう見ても問題が見えないかもしれませんが、多くの人がこのようなコードを書いたことがあると思います.大量のデータテストを使用するとメモリが上昇し続け、テストデータを2倍にすると、メモリも2倍に増加し、典型的なメモリ漏れが発生します.スタックpop()の操作をよく検討すると、スタックには参照できないオブジェクトが大量に存在することがわかります.スタックを出た後、要素は使用されなくなったとマークされていないため、size以降の要素はアクセスできない無効な参照オブジェクトになりますが、stackスタックオブジェクト自体が有効な参照であるため、これらの無効な参照はゴミ回収器で回収できません.メモリが漏れる.
上記の例のメモリリークを解決する方法も簡単で、再pop()方法は以下の通りです.
public Object pop(){
	if(size == 0){
	throw new EmptyStackException();
}
Object result = elements[--size];
elements[size] = null;//          null,             
return result;
}

Javaでメモリの漏洩が発生する場合と解決方法:
(1).長寿命の集合コンテナオブジェクトに無効な参照が多数存在する短いライフ要素オブジェクト:コンテナで使用されなくなったオブジェクトをnullとしてマークし、アクセスできない無効な参照が発生しないようにする.
(2).namingservice,cacheなどの汎用リソースサービス:タイミングクリーンアップ;WeakReference弱参照を使用します.WeakHashMap容器などを使用します.
(3).リスナーとcallbackコールバック関数.WeakReference弱参照を使用します.WeakHashMap容器などを使用します.