WeakHashMap如何工作 [英] How WeakHashMap works under the hood

查看:128
本文介绍了WeakHashMap如何工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我调查WeakHashMap ource代码以获得更多有关 WeakReference

的知识

我发现该条目看起来像这样:

  private static class Entry< K,V>扩展WeakReference< Object>实现Map.Entry< K,V> {
V值;
final int hash;
条目< K,V>下一个;

/ **
*创建新条目。
* /
Entry(Object key,V value,
ReferenceQueue< Object> queue,
int hash,Entry< K,V> next){
super密钥,队列);
this.value = value;
this.hash = hash;
this.next = next;




$ b $ p
$ b

因此,当我们创建新条目时,我们调用 super(key,queue); 。它是 WeakReference 构造函数。据我了解对象将被GC收集后,新的引用(我相信它应该引用 key )将出现在队列中。

另外我注意到了在每个操作上调用的方法:

pre $ code > / **
*从表格中删除陈旧的条目。
* /
private void expungeStaleEntries(){
for(Object x;(x = queue.poll())!= null;){
synchronized(queue){
@SuppressWarnings(unchecked)
条目< K,V> e =(Entry< K,V>)x;
int i = indexFor(e.hash,table.length);

条目< K,V> prev = table [i];
条目< 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;
//不能将e.next清空;
//过时的条目可能被HashIterator使用
e.value = null; //帮助GC
size--;
休息;
}
prev = p;
p = next;






就像我们从队列中得到(Entry< K,V>)。我不知道如何解释(第一个问题)。
这段代码:

pre $ public static void main(String [] args)throws InterruptedException {
StringBuilder AAA = new StringBuilder();
ReferenceQueue队列=新的ReferenceQueue();
WeakReference weakRef = new WeakReference(AAA,queue);
AAA = null;
System.gc();
引用removedReference = queue.remove();
System.out.println(removedReference.get());
}

总是输出null,因为GC已经收集到的对象



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

解决方案

队列返回之前创建的引用对象。因此,在执行

 后,您的示例代码可以参考removedReference = queue.remove(); 

表达式 removedReference == weakRef 会评估到 true ,因为这是您创建的唯一参考对象。通过这个测试,您可以得出结论,由于引用对象的身份,已经收集了以前由 AAA 引用的对象,所以您已经阅读了有意义的东西。

如果你想将更多的信息与它联系起来,一个可行的方法是创建一个 WeakReference 的子类,正是 WeakHashMap.Entry 的意思。在它的构造函数中,它调用 super(key,queue); ,它与您的表达式 new WeakReference(AAA,queue),第一个参数指定弱引用的对象。



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


I invesigate WeakHashMap ource code to have more knowledge about WeakReference

I have found that entry looks like this:

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;
        }
        ...

Thus when we create new entry we invoke super(key, queue);. It is WeakReference constructor. As far I understand after object will be collected by GC the new reference(I believe it should be reference on key) will be appeared in the queue.

Also I have noticed method which invokes on each operation:

    /**
     * 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;
                }
            }
        }
    }

Looks like we get (Entry<K,V>) from queue. I don't know how to explain this(first question). this code:

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

always outputs null, because object already collected by GC

Also for me it was strange that we can have reference on Object which was already collected by GC. Actually I expect that reference should appear in queue but I could not read something meaningful because object already collected(second question).

解决方案

The queue returns the very reference object, you have created before. So with your example code, after executing

Reference removedReference = queue.remove();

the expression removedReference == weakRef would evaluate to true, as that’s the only reference object you’ve ever created. With this test, you can already conclude that the object formerly referenced by AAA has been collected, due to the identity of the reference object, so you already read "something meaningful".

If you want to associate more information with it, a viable way is to create a subclass of WeakReference, which is exactly what WeakHashMap.Entry is about. In its constructor, it calls super(key, queue);, which is not different to your expression new WeakReference(AAA, queue), the first argument specifies the weakly referenced object.

So the garbage collector will enqueue the specialized WeakReference, i.e. Entry, object if its referent (the key) has become unreachable. At this point, the key can’t be retrieved anymore, i.e. its get() method will return null, but the method expungeStaleEntries() isn’t interested in the key anyway. It wants to remove the Entry instance from the table, allowing the garbage collector to reclaim the Entry instance itself and possibly the referenced value, if there are no other reference to it. It helps that this subclass has remembered the previously calculated hash code, so the map doesn’t need to search linearly.

这篇关于WeakHashMap如何工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆