0

WeakHashMap のコードを調査して、より多くの知識を得るWeakReference

エントリが次のようになっていることがわかりました。

private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> {
        V value;
        final int hash;
        Entry<K,V> next;

        /**
         * Creates new entry.
         */
        Entry(Object key, V value,
              ReferenceQueue<Object> queue,
              int hash, Entry<K,V> next) {
            super(key, queue);
            this.value = value;
            this.hash  = hash;
            this.next  = next;
        }
        ...

したがって、新しいエントリを作成するときは、 を呼び出しsuper(key, queue);ます。WeakReferenceコンストラクタです。オブジェクトがGCによって収集された後、私が理解している限り、新しい参照(上の参照であるべきだと思いますkey)がキューに表示されます。

また、各操作で呼び出すメソッドに気付きました:

    /**
     * Expunges stale entries from the table.
     */
    private void expungeStaleEntries() {
        for (Object x; (x = queue.poll()) != null; ) {
            synchronized (queue) {
                @SuppressWarnings("unchecked")
                    Entry<K,V> e = (Entry<K,V>) x;
                int i = indexFor(e.hash, table.length);

                Entry<K,V> prev = table[i];
                Entry<K,V> p = prev;
                while (p != null) {
                    Entry<K,V> next = p.next;
                    if (p == e) {
                        if (prev == e)
                            table[i] = next;
                        else
                            prev.next = next;
                        // Must not null out e.next;
                        // stale entries may be in use by a HashIterator
                        e.value = null; // Help GC
                        size--;
                        break;
                    }
                    prev = p;
                    p = next;
                }
            }
        }
    }

(Entry<K,V>)キューから取得したよう です。これを説明する方法がわかりません(最初の質問)。このコード:

public static void main(String[] args) throws InterruptedException {
    StringBuilder AAA = new StringBuilder();
    ReferenceQueue queue = new ReferenceQueue();
    WeakReference weakRef = new WeakReference(AAA, queue);
    AAA = null;
    System.gc();
    Reference removedReference = queue.remove();
    System.out.println(removedReference.get());
}

オブジェクトはすでにGCによって収集されているため、常にnullを出力します

また、私にとっては、GC によって既に収集されたオブジェクトを参照できることも奇妙でした。実際には、参照がキューに表示されるはずですが、オブジェクトが既に収集されているため、意味のあるものを読み取ることができませんでした ( 2 番目の質問)。

4

3 に答える 3

0

aReferenceQueueがポーリングされるとReference、参照先にオブジェクトが返されます。エンキュー操作は、キューReference#enqueueに追加することによって行われます。thisしたがって、 forWeakReferenceは拡張されているためReference、戻り値を にキャストできますWeakReference

したがって、WeakHashMap実装ではEntry<K, V>、 poll の戻り値が のサブクラスである のサブクラスであるWeakReferenceため、 poll の戻り値を にキャストできます。つまり、 はキューに追加されるため、実装では のインスタンスをキューに入れます。Entry<K, V>WeakReferenceReferenceReference#enqueuethisWeakHashMapEntry<K, V>

Entry<K, V>クラスはキーを参照しないことに注意してください。これは、強い参照につながるため、GC はキーをファイナライズしないためです。get通常の状況、つまりキーが強く参照されている場合にクエリを実行できるように、ハッシュのみを保持します。

于 2018-06-11T20:41:09.693 に答える
0

キューは、以前に作成したまさに参照オブジェクトを返します。あなたのコード例では、実行後に

Reference removedReference = queue.remove();

これまでに作成した唯一の参照オブジェクトであるため、式removedReference == weakRefは に評価されます。trueこのテストでAAAは、参照オブジェクトの同一性により、以前に によって参照されたオブジェクトが収集されたとすでに結論付けることができるため、既に「意味のあるもの」を読み取っています。

より多くの情報を関連付けたい場合、実行可能な方法は、 のサブクラスを作成するWeakReferenceことWeakHashMap.Entryです。そのコンストラクターではsuper(key, queue);、を呼び出します。これは、式と同じnew WeakReference(AAA, queue)です。最初の引数は、弱く参照されるオブジェクトを指定します。

そのため、ガベージ コレクタは、その参照対象 ( ) が到達不能になった場合、特殊化されたWeakReference、つまりEntry、オブジェクトをキューにkey入れます。この時点で、キーはもう取得できません。つまり、そのget()メソッドは を返しますnullが、とにかくメソッドexpungeStaleEntries()はキーに関心がありません。テーブルからインスタンスを削除してEntry、ガベージ コレクターがEntryインスタンス自体を再利用できるようにし、他の参照がない場合は参照された値を再利用できるようにします。このサブクラスが以前に計算されたハッシュ コードを記憶しているため、マップが直線的に検索する必要がありません。

于 2017-01-31T15:21:19.067 に答える