スポンサード リンク

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

スポンサード リンク
-- : -- : -- | スポンサー広告 | page top↑
スポンサード リンク

Javaでも起こりうるメモリリーク

Effective Java プログラミング言語ガイド」を読んでいたら、以前のエントリ「Javaで学ぶデータ構造入門01-スタック(2/3)-ジェネリクスの実装」で詳解したスタックのプログラムにはメモリリークの可能性があることに気付きました。

Javaではガベージ・コレクション(GC)が行われるため、メモリ管理をあまり意識することなくプログラムを書くことができますが、そこに大きな罠がありました。

まずは、次のプログラム(再掲)をご覧下さい。これを見て、どこにメモリリークの可能性が潜んでいるか見つけられるでしょうか?

public class MyStack {	
	private T[] stack;
	private int sp; /* stack pointer */
	private final static int DEFAULT_CAPACITY = 10;
	private int capacity;
	
	public MyStack() {
		this(DEFAULT_CAPACITY);
	}
	
	public MyStack(int initialCapacity) {
		capacity = initialCapacity;
		stack = (T[]) new Object[initialCapacity];
	}
	
	public void push(T item) {
		stack[sp++] = item;
		capacityCheck();
	}
	
	public T pop() {
		return stack[--sp];
	}
	
	private void capacityCheck() {
		if(sp >= capacity)
			expandCapacity();
	}

	private void expandCapacity() {
		capacity *= 2;
		Object[] oldStack = stack;
		stack = (T[]) new Object[capacity];
		System.arraycopy(oldStack, 0, stack, 0, sp);
	}
}

このプログラムではスタックを配列によって実装しており、pushされるたびに新しいオブジェクトが配列に格納されていきます。そして、配列がいっぱいになると、expandCapacityを呼び出して配列を大きくします。

しかし、popされたときはスタックポインタの値をデクリメントして、スタックの先頭要素をreturnするだけなので、見かけ上はスタックから要素が取り除かれていますが、実際には配列に格納されたままなので参照は維持されています。

ガーベジ・コレクタはどこからも参照されていないオブジェクトを回収の対象に選びますので、このような実際には使われなくなったけど参照されたまま(※この状態をEffective Javaでは「廃れた参照(obsolete reference)」と呼んでいます)のオブジェクトは回収することができません。

こうして、使われなくなったのに回収してもらえないオブジェクトが増えていくと、しまいにはメモリリークを起こしてしまう可能性があります。(※しかし、最近のマシンはメモリ量が多いため、よほど使いすぎない限りメモリが足りなくなって止まってしまう可能性はないと思います)

さて、popの実装に問題があることはわかりましたがどのように修正をすればいいのでしょうか?実は簡単です。要は、参照が廃れたらそのことを明示すればよいので、popの際にreturnした要素が入っていた領域にnullをセットするようにします。

	public T pop() {
		Object result = stack[--sp];
		stack[sp] = null;
		return result;
	}
Effective Java プログラミング言語ガイドEffective Java プログラミング言語ガイド
Joshua Bloch

ピアソン・エデュケーション 2001-12-03
売り上げランキング : 2841
おすすめ平均

Amazonで詳しく見る
by G-Tools

スポンサード リンク

テーマ:プログラミング - ジャンル:コンピュータ - ソーシャルブックマーク: この記事をクリップ! Yahoo!ブックマークに登録

13 : 46 : 13 | プログラミング-Java | トラックバック(0) | コメント(0) | page top↑
<<正確な値が要求される計算にfloat,double型は使えない! | ホーム | 待ち行列のM/M/1モデルにおける平均滞在時間Wwの導出>>
コメント

コメントの投稿














管理者にだけ表示を許可する

トラックバック
トラックバックURL
http://networkprogramming.blog18.fc2.com/tb.php/74-021735ea
この記事にトラックバックする(FC2ブログユーザー)
| ホーム |

プロフィール

TBVector

Author:TBVector

プロフィール

メールフォーム

記事検索

Google

最近の記事

人気の記事

過去の記事

カテゴリー

タグランキング

リンク

最近のコメント

最近のトラックバック

アクセスカウンタ

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。