【问题标题】:How WeakHashMap works under the hoodWeakHashMap 如何在后台工作
【发布时间】:2017-01-29 09:28:36
【问题描述】:

我研究了 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&lt;K,V&gt;)。我不知道如何解释这个(第一个问题)。 这段代码:

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());
}

总是输出 null,因为对象已经被 GC 收集了

对我来说也很奇怪,我们可以对已经被 GC 收集的 Object 进行引用。实际上我希望引用应该出现在队列中,但我无法读取有意义的内容,因为对象已经收集(第二个问题)。

【问题讨论】:

  • @downvoter,我在文本中明确添加了我想澄清的内容
  • 您是否查看过与 ReferenceQueue 相关的其他 SO 问题?
  • @the8472 我没有看到相关标签
  • 不是标签,只搜索ReferenceQueue

标签: java garbage-collection weak-references weakhashmap


【解决方案1】:

看起来我们从队列中获得(条目)。我不知道怎么解释这个

queue.poll() 为您提供通过引用构造函数放入队列的引用实例。在这种情况下,它是Entry&lt;K,V&gt; extends WeakReference&lt;Object&gt;

实际上我希望引用应该出现在队列中,但我无法读取有意义的内容,因为对象已经收集

您会得到 Reference 对象本身,您可以使用它来进行一些清理,或者通过子类化或将其与其他数据相关联,例如通过辅助Map。你可以通过get 在它还活着的时候获得的裁判无关紧要,Reference 对象本身就是。

【讨论】:

  • 为什么要放 Entry
  • gc 如何理解与 Entry 而不仅仅是 WeakReference 相关的键?
  • 这些是新问题。我建议在 SO 上阅读 javadocs 或研究与ReferenceQueue 相关的其他示例,有比WeakHashMap 更简单的示例
  • 更简单的例子对我来说很清楚。我不明白继承
【解决方案2】:

队列返回您之前创建的引用对象。因此,使用您的示例代码,在执行后

Reference removedReference = queue.remove();

表达式removedReference == weakRef 将计算为true,因为这是您创建的唯一引用对象。通过这个测试,您已经可以得出结论,由于引用对象的身份,之前AAA 引用的对象已被收集,因此您已经阅读了“有意义的东西”。

如果您想将更多信息与之关联,一个可行的方法是创建WeakReference 的子类,这正是WeakHashMap.Entry 的意义所在。在它的构造函数中,它调用super(key, queue);,这和你的表达式new WeakReference(AAA, queue)没有什么不同,第一个参数指定了弱引用的对象。

因此,如果其引用对象(key)变得无法访问,垃圾收集器会将专用的WeakReference(即Entry)对象排入队列。此时,无法再检索密钥,即其get() 方法将返回null,但方法expungeStaleEntries() 无论如何对密钥不感兴趣。它想从表中删除Entry 实例,允许垃圾收集器回收Entry 实例本身以及可能的引用值,如果没有其他引用的话。这有助于这个子类记住之前计算的哈希码,因此地图不需要线性搜索。

【讨论】:

    【解决方案3】:

    ReferenceQueue 被轮询时,它将返回一个Reference 对象给所指对象。入队操作由Reference#enqueue 完成,它将this 添加到队列中。因此,对于WeakReference,由于它扩展了Reference,因此可以将返回值强制转换为WeakReference

    因此,在WeakHashMap 实现中,由于Entry&lt;K, V&gt; 扩展了WeakReference,poll 的返回值可以转换为Entry&lt;K, V&gt;,因为它是WeakReference 的子类,而Reference 的子类。换句话说,Reference#enqueue 将添加到队列this 中,因此在WeakHashMap 实现中,它会将Entry&lt;K, V&gt; 的实例加入队列。

    请注意,Entry&lt;K, V&gt; 类没有引用 key,因为它会导致强引用,因此 GC 不会最终确定它。它只保留哈希,以便在正常情况下(即强引用键时)可以执行对 get 的查询。

    【讨论】:

      猜你喜欢
      • 2019-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-23
      • 2020-11-06
      • 2018-10-30
      相关资源
      最近更新 更多