您误会了情况。当
map.values().contains(meta)或short
map.containsValue(meta)返回时
false,并不表示
meta已被垃圾回收。实际上,您在其中持有对该对象的引用
meta,甚至将该引用传递给
contains可能
equals在其上调用的方法。那么该对象如何被垃圾回收?
该响应仅告诉您映射的键之一与该对象之间没有关联,并且由于唯一的键已被垃圾回收,因此这是正确的答案。或者,您可能只是要求
map.isEmpty()检查关联的存在。
这是
WeakHashMap提供的:
基于哈希表的
Map接口实现,带有 弱键
。当a中的某个条目WeakHashMap不再用作其键时,该条目将自动删除。更准确地说,给定键的映射的存在不会阻止该键被垃圾收集器丢弃,即被终结化,终结化和回收。丢弃键后,其条目会从映射中有效删除,因此此类的行为与其他Map实现有所不同。
条目的删除不是瞬时的。它依赖于将排队
WeakReference到a中
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");尽管
Person此时已证明关键实例已被垃圾回收,但它偶尔还是打印“ Value present”
。如上所述,这与地图的内部清理有关,而不是与
Personmetadata我们始终保持强烈引用的实例有关
meta。
使有
Personmetadata资格进行垃圾回收是完全不同的事情。如前所述,
WeakReference每当我们调用方法an时,都会进行内部清理。如果我们不这样做,就不会进行清理,因此即使密钥已被垃圾回收,它仍然是一个强大的参考。考虑:
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 collectedPersonmetadata not collectedPersonmetadata not collectedPersonmetadata not collectedPersonmetadata not collectedPersonmetadata not collectedPersonmetadata not collectedPersonmetadata not collectedPersonmetadata not collectedPersonmetadata not collectedPersonmetadata not collectedcalling a query method on mapmap.size() == 0Personmetadata collected
演示在
WeakHashMap最终调用该方法之前,该方法如何强烈引用已收集键的值,从而使它有机会执行其内部清理。
当
WeakHashMap方法或我们的方法都没有引用它时,最终会收集该值。当我们删除该
meta =null;语句时,该映射在最后(内部清除之后)仍将为空,但不会收集该值。
重要的是要记住,这些代码示例仅用于演示目的并涉及特定于实现的行为,最值得注意的是,
main方法通常未优化运行。正式地,如果未使用引用对象,则不需要局部变量来防止垃圾收集,这在优化方法时实际上具有相关性。



