2010年5月8日土曜日

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

いろいろ忙しい・・。
友達が家の近くに引越してきました。
意外と家賃が安くてショックです。

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

前回、廃れた参照を排除する最善の方法は、その参照が含まれた変数を再利用するか、その変数のスコープ外にでること、という事まで書きました。

現在のjvm実装では、変数が定義されているブロックから抜けるだけでは充分ではなく、参照を消すためには、その変数が含まれるメソッドから抜け出す必要があるので注意が必要です。

では、どのような時に参照にnullを設定するべきでしょうか。

簡単に言えば、前回例として記述したstackのように、プログラマが独自にメモリ管理を行っている場合です。
stackは、配列のある要素が無効になった場合、そのことをガーベージコレクタに知らせるためにnullを設定します。
それ以外、ガーベージコレクタがstackの要素が無効になった事を知る術はありません。つまり、nullを設定しないと、そのメモリは開放されないため、メモリリークの原因となります。

上記以外によくあるメモリリークの原因は、キャッシュです。

オブジェクト参照を一旦キャッシュにいれてしまうと、オブジェクト参照がそこにあることを忘れがちですし、そのオブジェクト参照の意味がなくなったかなり後でも、キャッシュに残したままにしがちです。

この問題に対しては、2つの解決方法があります。

1つは、キャッシュ対象のエントリに対するキーへの参照を、キャッシュ自身以外が保持していることに意味がある場合、そのキャッシュをWeakHashMapで実現することです。

WeakHashMapはキーを弱参照で保持するため、エントリーに対するキーへの参照がキャシュ外に存在しなくなった場合、そのエントリーはガーベージコレクト対象となります。
他のMapはキーを強参照で保持するため、上記のような状態となっても、エントリーはガーベージコレクト対象となりません。

弱参照と強参照の違いは、以下のコードを見るとわかりやすいです。
-----------------------------------------------------------
■ 実験コード

1 Integer key = new Integer(1);
2
3 Map cache = new HashMap(); //キャッシュをHashMapで実装
4 cache.put(key, "entry");
5
6 key = null; //エントリーに対するキー値の参照にnullを設定
7
8 System.gc(); //強制的にGCを実施
9
10 System.out.println(cache.get(new Integer(1)));
-----------------------------------------------------------
実行結果として、「entry」が出力されます。
3行目のキャッシュをWeakHashMapで実装した場合、「null」が出力されます。
6行目でエントリーに対するキーへの参照が存在しなくなるため、紐づくエントリーがガーベージコレクトされたためです。

---> 更に続く・・意外と長い;;

0 件のコメント:

コメントを投稿