为什么WeakHashMap在GC之后拥有强大的价值参考? [英] Why WeakHashMap holds strong reference to value after GC?
问题描述
WeakHashMap中的关键对象变得无法访问。并且地图应该在GC之后删除条目。但是对价值对象的强烈提及仍然存在。为什么?
Key object in WeakHashMap became weakly reachable. And map should be remove the entry after GC. But a strong reference to the value object remains. Why?
使用番石榴弱键映射会发现相同的行为。
The same behavior is observed with guava weakkeys map.
预期输出:
...
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());
}
}
UPD:
我尝试在jСonsole和jcmd中执行GC但输出没有改变。
I tried perform GC in jСonsole and jcmd but output was not changed.
推荐答案
WeakHashMap
包含 Map.Entry
实例,它们使用<引用密钥code> WeakReference (实际上,在OpenJDK / Oracle JDK中,它直接扩展 WeakReference
。
The WeakHashMap
contains Map.Entry
instances which reference the key using a WeakReference
(actually, in OpenJDK / Oracle JDK, it directly extends WeakReference
).
当GC发生时,现在引用缺席键的条目不会从地图中神奇地删除:它们在被清除之前仍然存在,这就是为什么该值仍然存在并具有尚未收集。
When the GC happens, the entries which now reference absent keys are not magically removed from the map: they're still present until cleared, which is why the value is also still present and has not been collected yet.
在OpenJDK中,发生在 expungeStaleEntries()
使用 ReferenceQueue
,并从多个地方调用该方法:
In OpenJDK, that happens in expungeStaleEntries()
using a ReferenceQueue
, and that method is called from a number of places:
-
size()
-
resize()
-
getTable()
本身是从多种方法调用的,包括get()
和put()
size()
resize()
getTable()
which is itself called from multiple methods, includingget()
andput()
如果您希望您的值是垃圾收集的,您应该与 WeakHashMap
进行交互,例如通过询问 size()
或进行查找。
If you want your value to be garbage collectable, you should interact with the WeakHashMap
, e.g. by asking for its size()
or doing a lookup.
请注意,这意味着无法收集该值第二次垃圾收集。
Note that it means the value cannot be collected until a second garbage collection.
如果我没记错的话,它在Guava中的工作方式大致相同。
If I remember correctly, it works more or less the same way in Guava.
这篇关于为什么WeakHashMap在GC之后拥有强大的价值参考?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!