问题描述
首先我想澄清我对 WeakReference
的理解,因为以下问题取决于相同的问题.
First of all I would like to clarify my understanding of the WeakReference
as the following question depends on the same.
static void test() {
Person p = new Person();
WeakReference<Person> person = new WeakReference<>(p);
p = null;
System.gc();
System.out.println(person.get());
System.out.println(person);
}
static class Person {
String name;
}
static class PersonMetadata {
String someData;
public PersonMetadata(String met) {
someData = met;
}
}
上面代码的输出是
空java.lang.ref.WeakReference@7852e922
这意味着虽然实际的 person 对象在 GC 运行后被垃圾收集,但内存中存在一个 WeakReference
类的对象,它不指向任何东西这一点.
Which means that although there is the actual person object is garbage collected once a GC runs, there is an object of WeakReference<Person>
class is there in the memory which does not point to anything at this point.
现在考虑到上述理解是正确的,我对 WeakHashMap<K,V>
的工作原理感到困惑.在下面的代码中
Now considering the above understanding true, I am confused about how does WeakHashMap<K,V>
works. In the below code
public static void main(String[] args) {
Person p = new Person();
p.name = "John";
WeakHashMap<Person, PersonMetadata> map = new WeakHashMap<>();
PersonMetadata meta = new PersonMetadata("Geek");
map.put(p, meta);
p = null;
System.gc();
if (map.values().contains(meta)) {
System.out.println("Value present");
} else {
System.out.println("Value gone");
}
}
static class Person {
String name;
}
static class PersonMetadata {
String someData;
public PersonMetadata(String met) {
someData = met;
}
}
输出: 价值消失
现在的问题 据说 WeakHashMap
中的键是弱引用,这意味着在上面的代码中 p
变为 null
实际对象可以被垃圾回收,因为没有更多对该对象的强引用,但 和值如何这是 PersonMetadata
类的对象正在被垃圾收集,因为第一个代码证明 WeakReference
类的对象没有被垃圾收集,即使实际对象已被收集.
Now the the question is as it is said that the key in WeakHashMap<K,V>
is an weak reference which means that in the above code when p
becomes null
the actual object can be garbage collected as there is no more strong reference to the object, but how does the and the value which is an object of PersonMetadata
class is getting garbage collected as the first code proves that object of WeakReference
class is not garbage collected even though the actual object is collected.
推荐答案
你误会了情况.当 map.values().contains(meta)
或短 map.containsValue(meta)
返回 false
时,并不意味着meta
已被垃圾回收.实际上,您在 meta
中持有对对象的引用,甚至将该引用传递给可能在其上调用 equals
的 contains
方法.那么这个对象怎么会被垃圾回收呢?
You are misunderstanding the situation. When map.values().contains(meta)
, or short map.containsValue(meta)
returns false
, it doesn’t imply that meta
has been garbage collected. In fact, you are holding a reference to the object in meta
and even passing that reference to the contains
method which may invoke equals
on it. So how could that object be garbage collected?
响应仅告诉您映射的一个键与该对象没有关联,并且由于唯一的键已被垃圾回收,因此这是正确的答案.或者,您可以只要求 map.isEmpty()
检查关联是否存在.
The response only tells you that there is no association from one of the map’s keys to that object and since the only key has been garbage collected, that’s the correct answer. Alternatively, you could just have asked map.isEmpty()
to check for the presence of the association.
这就是 WeakHashMap
提供:
This is what the WeakHashMap
provides:
Map
接口的基于哈希表的实现,带有弱键.WeakHashMap
中的条目在其键不再正常使用时将被自动删除.更准确地说,给定键的映射的存在不会阻止该键被垃圾收集器丢弃,也就是说,使其可终结,最终确定,然后回收.当一个键被丢弃时,它的条目实际上从映射中删除,所以这个类的行为与其他 Map
实现有些不同.
Hash table based implementation of the
Map
interface, with weak keys. An entry in aWeakHashMap
will automatically be removed when its key is no longer in ordinary use. More precisely, the presence of a mapping for a given key will not prevent the key from being discarded by the garbage collector, that is, made finalizable, finalized, and then reclaimed. When a key has been discarded its entry is effectively removed from the map, so this class behaves somewhat differently from otherMap
implementations.
条目的删除不是即时的.它依赖于将 WeakReference
排队到 ReferenceQueue
中,然后在您进行下一个查询时在内部对其进行轮询,例如 containsValue
甚至 >尺寸()代码>.例如.如果我将您的程序更改为:
The removal of the entry is not instantaneous. It relies on enqueuing of the WeakReference
into a ReferenceQueue
, which is then polled internally when you make the next query, like containsValue
or even size()
. E.g. if I change your program to:
Person p = new Person();
WeakHashMap<Person, PersonMetadata> map = new WeakHashMap<>();
PersonMetadata meta = new PersonMetadata("Geek");
map.put(p, meta);
WeakReference<?> ref = new WeakReference<>(p);
p = null;
while(ref.get() != null) System.gc();
System.out.println(map.containsValue(meta)? "Value present": "Value gone");
尽管关键 Person
实例已被证明已被垃圾回收,但它偶尔会打印Value present".如上所述,这是关于地图的内部清理,而不是关于我们在 meta
中持有强引用的 PersonMetadata
实例.
It occasionally prints "Value present" despite the key Person
instance provenly has been garbage collected at this point. As said above, this is about the map’s internal cleanup, not about the PersonMetadata
instance to which we’re holding a strong reference in meta
anyway.
使 PersonMetadata
有资格进行垃圾回收是完全不同的事情.如前所述,每当我们调用一个方法时,WeakReference
都会进行内部清理.如果我们不这样做,将不会进行清理,因此即使密钥已被垃圾收集,仍然是一个强引用.考虑:
Making PersonMetadata
eligible to garbage collection is an entirely different thing. As said, the WeakReference
does an internal cleanup whenever we call a method an it. If we don’t, there will be no cleanup and hence, still a strong reference, even if the key has been garbage collected. Consider:
Person p = new Person();
WeakHashMap<Person, PersonMetadata> map = new WeakHashMap<>();
PersonMetadata meta = new PersonMetadata("Geek");
map.put(p, meta);
WeakReference<?> personRef = new WeakReference<>(p);
WeakReference<?> metaRef = new WeakReference<>(meta);
p = null;
meta = null;
while(personRef.get() != null) System.gc();
System.out.println("Person collected");
for(int i = 0; metaRef.get() != null && i < 10; i++) {
System.out.println("PersonMetadata not collected");
System.gc();
Thread.sleep(1000);
}
System.out.println("calling a query method on map");
System.out.println("map.size() == "+map.size());
System.gc();
System.out.println("PersonMetadata "+(metaRef.get()==null? "collected": "not collected"));
哪个会打印
Person collected
PersonMetadata not collected
PersonMetadata not collected
PersonMetadata not collected
PersonMetadata not collected
PersonMetadata not collected
PersonMetadata not collected
PersonMetadata not collected
PersonMetadata not collected
PersonMetadata not collected
PersonMetadata not collected
calling a query method on map
map.size() == 0
PersonMetadata collected
演示 WeakHashMap
如何保持对已收集键的值的强引用,直到我们最终调用它的方法,让它有机会执行其内部清理.
demonstrating how the WeakHashMap
holds a strong reference to the value of an already collected key until we eventually invoke a method on it, to give it a chance to perform its internal cleanup.
当 WeakHashMap
和我们的方法都没有持有对它的引用时,该值最终被收集.当我们删除 meta = null;
语句时,地图最后仍然是空的(在其内部清理之后),但不会收集值.
The value finally gets collected when neither, the WeakHashMap
nor our method, hold a reference on it. When we remove the meta = null;
statement, the map still will be empty at the end (after its internal cleanup), but the value won’t be collected.
请务必记住,这些代码示例是出于演示目的并涉及特定于实现的行为,最值得注意的是,main
方法通常在未经优化的情况下运行.形式上,如果所指对象未被使用,则不需要局部变量来防止垃圾收集,这一点在方法优化后的实践中具有相关性.
It’s important to keep in mind that these code examples are for demonstration purposes and touch implementation specific behavior, most notably, that a main
method usually runs unoptimized. Formally, local variables are not required to prevent garbage collection if the referent is otherwise unused, a point which has relevance in practice when methods have been optimized.
这篇关于当实际对象被垃圾收集时,WeakHashMap 中的条目中的值如何被垃圾收集?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!