[英]How WeakHashMap works under the hood
I invesigate WeakHashMap ource code to have more knowledge about WeakReference
我研究WeakHashMap我们的代码以了解有关
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);
因此,当我们创建新条目时,我们调用
super(key, queue);
. 。 It is
WeakReference
constructor. 它是
WeakReference
构造函数。 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. 据我了解,GC将收集对象之后 ,新引用(我相信应该是
key
上的引用)将出现在队列中。
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. 看起来我们从队列中得到了
(Entry<K,V>)
。 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 始终输出null,因为GC已经收集了对象
Also for me it was strange that we can have reference on Object which was already collected by GC. 同样让我感到奇怪的是,我们可以引用GC已经收集的Object。 Actually I expect that reference should appear in queue but I could not read something meaningful because object already collected( second question ).
实际上,我希望引用应该出现在队列中,但是由于对象已被收集( 第二个问题 ),我无法读取有意义的内容。
Looks like we get (Entry) from queue.
看起来我们从队列中获得了(条目)。 I don't know how to explain this
我不知道该怎么解释
queue.poll()
gives you the reference instances you put into the queue through the reference constructor. queue.poll()
为您提供了通过引用构造函数放入队列中的引用实例。 In this case it's Entry<K,V> extends WeakReference<Object>
. 在这种情况下,它的
Entry<K,V> extends WeakReference<Object>
。
Actually I expect that reference should appear in queue but I could not read something meaningful because object already collected
实际上,我希望引用应该出现在队列中,但是我无法读取有意义的内容,因为对象已被收集
You get the Reference
object itself which you can use to do some cleanup, either through subclassing or by associating it with additional data eg through an auxiliary Map
. 您可以获取
Reference
对象本身,可以通过子类化或通过将其与其他数据关联(例如通过辅助Map
来进行一些清理。 The referee you can obtain through get
while it is still alive is not relevant, the Reference
object itself is. 您可以通过
get
仍然活着获取的裁判与此无关, Reference
对象本身与此无关。
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. 表达式
removedReference == weakRef
计算结果为true
,因为这是您创建的唯一参考对象。 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”. 通过此测试,您可以得出结论,由于引用对象的身份,先前由
AAA
引用的对象已被收集,因此您已经阅读了“有意义的内容”。
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. 如果您想与它关联更多信息,一种可行的方法是创建
WeakReference
的子类,而这正是WeakHashMap.Entry
目的。 In its constructor, it calls super(key, queue);
在其构造函数中,它调用
super(key, queue);
, which is not different to your expression new WeakReference(AAA, queue)
, the first argument specifies the weakly referenced object. ,与您的表达式
new WeakReference(AAA, queue)
,第一个参数指定了弱引用的对象。
So the garbage collector will enqueue the specialized WeakReference
, ie Entry
, object if its referent (the key
) has become unreachable. 因此,如果垃圾回收的
WeakReference
对象( key
)变得不可访问,则垃圾回收器会将其放入专用的WeakReference
,即Entry
对象。 At this point, the key can't be retrieved anymore, ie its get()
method will return null
, but the method expungeStaleEntries()
isn't interested in the key anyway. 此时,无法再检索到密钥,即其
get()
方法将返回null
,但方法expungeStaleEntries()
始终对密钥不感兴趣。 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. 它希望从表中删除
Entry
实例,如果没有其他引用,则垃圾回收器可以回收Entry
实例本身以及可能的引用值。 It helps that this subclass has remembered the previously calculated hash code, so the map doesn't need to search linearly. 这有助于该子类记住先前计算的哈希码,因此地图不需要线性搜索。
When a ReferenceQueue
is polled it will return a Reference
object to the referent. 轮询
ReferenceQueue
,它将把Reference
对象返回给被Reference
对象。 The enqueue operation is done by Reference#enqueue
which adds this
to the queue. 入列操作是由做
Reference#enqueue
这增加了this
队列。 Thus, for WeakReference
, since it extends Reference
the return value can be cast to WeakReference
. 因此,对于
WeakReference
,由于它扩展了Reference
,因此可以将返回值WeakReference
为WeakReference
。
So, in the WeakHashMap
implementation since the Entry<K, V>
extends WeakReference
the return value for poll can be cast to Entry<K, V>
as it is a subclass of WeakReference
which is a subclass of Reference
. 因此,在
WeakHashMap
实现中,由于Entry<K, V>
扩展了WeakReference
,因此轮询的返回值可以转换为Entry<K, V>
因为它是WeakReference
的子类,而WeakReference
是Reference
的子类。 In other words, the Reference#enqueue
will add to queue this
thus in the WeakHashMap
implementation it will enqueue the instance of Entry<K, V>
. 换言之,该
Reference#enqueue
将添加到队列this
因而在WeakHashMap
执行将排队的实例Entry<K, V>
Do note that the class Entry<K, V>
doesn't refer to key since it will lead to strong reference and thus GC will not finalize it. 请注意,类
Entry<K, V>
不会引用key,因为它将导致强引用,因此GC将不会最终确定它。 It only keeps the hash so that query for get
can be executed under normal circumstances ie when the key is strongly referenced. 它仅保留哈希值,以便可以在正常情况下(即强烈引用键的情况下)执行对
get
查询。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.