Dib*_*ndu 6 java collections garbage-collection weak-references weakhashmap
首先,我想澄清我对 的理解,WeakReference因为以下问题取决于相同。
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;
}
}
Run Code Online (Sandbox Code Playgroud)
上面代码的输出是
null
java.lang.ref.WeakReference@7852e922
这意味着虽然有一个实际的 person 对象在 GC 运行时被垃圾收集,但是WeakReference<Person>内存中存在一个类的对象,此时它不指向任何东西。
现在考虑到上述理解是正确的,我对它的WeakHashMap<K,V>工作原理感到困惑。在下面的代码中
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;
}
}
Run Code Online (Sandbox Code Playgroud)
输出: Value gone
现在的问题是,据说关键WeakHashMap<K,V>是一个弱引用,这意味着在上面的代码中,当p成为null实际对象时可以被垃圾收集,因为没有对该对象的强引用,但是如何作为PersonMetadata类对象的值正在被垃圾收集,因为第一个代码证明WeakReference即使收集了实际对象,类的对象也没有被垃圾收集。
你误解了情况。Whenmap.values().contains(meta)或 short map.containsValue(meta)return false,并不意味着meta已被垃圾收集。事实上,您持有对对象的引用meta,甚至将该引用传递给contains可能调用equals它的方法。那么该对象如何被垃圾回收呢?
响应仅告诉您从映射的键之一到该对象没有关联,并且由于唯一的键已被垃圾收集,因此这是正确的答案。或者,您可以只要求map.isEmpty()检查关联是否存在。
这是WeakHashMap提供的内容:
基于哈希表的
Map接口实现,带有弱键。当 a 中的条目WeakHashMap不再正常使用时,该条目将被自动删除。更准确地说,给定键的映射的存在不会阻止该键被垃圾收集器丢弃,即使其可终结、终结,然后被回收。当一个键被丢弃时,它的条目被有效地从映射中删除,所以这个类的行为与其他Map实现有些不同。
条目的删除不是即时的。它依赖于入队WeakReferencea ReferenceQueue,然后在您进行下一个查询时在内部进行轮询,例如containsValue甚至size()。例如,如果我将您的程序更改为:
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");
Run Code Online (Sandbox Code Playgroud)
它偶尔会打印“Value present”,尽管此时关键Person实例已被证明已被垃圾收集。如上所述,这是关于地图的内部清理,而不是关于PersonMetadata我们持有强引用的实例meta。
让PersonMetadata垃圾收集有资格是完全不同的事情。如上所述,WeakReference每当我们调用方法时,都会进行内部清理。如果我们不这样做,就不会进行清理,因此,即使键已被垃圾收集,仍然是强引用。考虑:
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"));
Run Code Online (Sandbox Code Playgroud)
哪个会打印
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");
Run Code Online (Sandbox Code Playgroud)
演示如何在WeakHashMap我们最终对其调用方法之前保持对已收集键的值的强引用,以使其有机会执行其内部清理。
当WeakHashMap或者我们的方法都没有引用它时,该值最终会被收集。当我们删除该meta = null;语句时,映射在最后(在其内部清理之后)仍然是空的,但不会收集该值。
重要的是要记住,这些代码示例用于演示目的和触摸实现特定行为,最值得注意的是,main方法通常未优化运行。形式上,如果所指对象未使用,则不需要局部变量来防止垃圾收集,这一点在优化方法时在实践中具有相关性。
| 归档时间: |
|
| 查看次数: |
437 次 |
| 最近记录: |