7

WeakHashMap の Key オブジェクトが弱く到達可能になりました。そしてマップは、GC の後にエントリを削除する必要があります。ただし、値オブジェクトへの強い参照は残ります。なんで?

guava の weakkeys マップでも同じ動作が見られます。

期待される出力:

...
refKey.get = null
refValue.get = null

しかし、私は出力を得ます:

map.keys = []
map.values = []
map.size = 0
refKey.get = null
refValue.get = (123)

コード:

import java.lang.ref.WeakReference;
import java.util.Map;
import java.util.WeakHashMap;
import com.google.common.collect.MapMaker;

public class Test {

    static class Number {
        final int number;
        public Number(int number) { this.number = number; }
        public String toString() { return "(" + number + ")"; }
    }

    static class Key extends Number {
        public Key(int number) { super(number); }
    }

    static class Value extends Number {
        public Value(int number) { super(number); }
    }

    public static void main(String args[]) {

        //Map<Key, Value> map = new MapMaker().weakKeys().makeMap();
        Map<Key, Value> map = new WeakHashMap<>();

        Key key = new Key(1);
        Value value = new Value(123);

        map.put(key, value);

        WeakReference<Key> refKey = new WeakReference<>(key);
        WeakReference<Value> refValue = new WeakReference<>(value);

        key = null;
        value = null;

        System.gc();

        System.out.println("map.keys = " + map.keySet());
        System.out.println("map.values = " + map.values());
        System.out.println("map.size = " + map.size());
        System.out.println("refKey.get = " + refKey.get());
        System.out.println("refValue.get = " + refValue.get());

    }

}

更新:

jСonsole と jcmd で GC を実行しようとしましたが、出力は変わりませんでした。

4

3 に答える 3

2

このコードの変更を実行し、Jconsole で GC を強制すると、参照の削除が確認されます。

    System.gc();

    try {
        while (refValue.get() != null) {
            System.out.println("map.keys = " + map.keySet());
            Thread.sleep(5000);
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    System.out.println("map.keys = " + map.keySet());
    System.out.println("map.values = " + map.values());
    System.out.println("map.size = " + map.size());
    System.out.println("refKey.get = " + refKey.get());
    System.out.println("refValue.get = " + refValue.get());

しかし、何らかの理由map.keySet()で、ループ内で が照会されない場合、決して終了しない、つまり にはrefValueなりませんnull

于 2016-01-19T14:18:53.623 に答える
1

Java では GC を制御できません。VM が決定します。System.gc() が必要なケースに遭遇したことはありません。System.gc() 呼び出しは、VM がガベージ コレクションを実行し、完全なガベージ コレクション (複数世代ヒープ内の古い世代と新しい世代) も実行することを単に示唆しているため、実際には、より多くの CPU サイクルが消費される可能性があります。必要。

jdk 1.7以降では、以下のコマンドを使用してgcを強制的に実行できます

jcmd <pid> GC.run

を使用してプロセス ID を取得するjps

于 2016-01-19T13:38:32.050 に答える