技術日誌

DB,Java,セキュリティ,機械学習など。興味のあることを雑多に学ぶ

Effective Java Item 7: Eliminate obsolete object references

廃れた参照は除くべし。

Effective Java (3rd Edition)

Effective Java (3rd Edition)

この項目の要約は

  • JavaGCあるけど思わぬ参照が残ることによってメモリリークが発生する恐れがある。だから廃れた参照を除きましょう。

でいいとして。。。 中に書かれているWeakHashMapが見慣れないので検証

こんな感じで生徒のリストとブラックリストを持っているクラスがあるとする

public class School {
    Map<String, String> studentList;
    Map<String, String> blackList;
    public School(Map<String, String> studentList, Map<String, String> blackList) {
        super();
        this.studentList = studentList;
        this.blackList = blackList;
    }
    public void registBlackList(String key) {
        if (studentList.containsKey(key)){
            blackList.put(key,studentList.get(key)); 
        }
    }
}

このコードに利用するmapのインスタンスとして

を与える

School instance = new Code7(new WeakHashMap<>(),new HashMap<>());

生徒を登録する*1

String studentNo1 = new String("1");
String studentNo2 = new String("2");
String studentNo3 = new String("3");
        
instance.studentList.put(studentNo1,new String("田中太郎"));
instance.studentList.put(studentNo2,new String("山田太郎"));
instance.studentList.put(studentNo3,new String("佐藤太郎"));

不良生徒をブラックリストに登録する

instance.registBlackList(studentNo3);

ここで内容を出力*2

studentList={1=田中太郎, 2=山田太郎, 3=佐藤太郎}blackList={3=佐藤太郎}

強参照を全て削除し、GCを実行する

     //強参照を全て消す
studentNo1 = null;
studentNo2 = null;
studentNo3 = null;

//GCを動かす
System.gc()

再び内容を出力

studentList={3=佐藤太郎}blackList={3=佐藤太郎}

何が起こっているか?

WeakHashMapは弱い参照(WeakReference)を利用しているため

WeakReference (Java SE 9 & JDK 9 )   WeakReference以外の参照がない場合はGCの対象となりうる。 ガベージコレクションを呼んだ時に佐藤はblackListからの参照(WeakReference以外)があったため 回収の対象とならずにすんだ。

WeakReferenceのコードでの使い方

Java弱参照メモ(Hishidama's Java Weak reference Memo)

このサイトでは - WeakReferenceコンストラクタに弱参照にしたいコードを渡す - getメソッドで取り出す

という使い方を紹介しているが、

WeakHashMapの実装を見たけど、コードの中ではEntiryの基底クラスをWeakReferenceにしていた。

private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> {

WeakReferenceにしたい場合はWeakReferenceのサブクラスとして実装する手もあるようだ。

*1:Stringクラスのコンストラクタを使わないと意図通の再回収の対象とならなかった。多分String poolが絡んでると思う。

*2:toStringの実装は略