WeakHashMap解决了什么问题?
设计WeakHashMap类是为了解决一个有趣的问题。如果有一个值,对应的键已经不再使用了,将会出现什么情况呢?假定对某个键的最后一次引用已经消亡,不再有任何途径引用这个值的对象了。但是,由于在程序中的任何部分没有再出现这个键,所以,这个键/值对无法从映射中删除。为什么垃圾回收器不能够删除它呢?难道删除无用的对象不是垃圾回收器的工作吗?
遗憾的是,事情没有这样简单。垃圾回收器跟踪活动的对象。只要映射对象是活动的,其中的所有桶也是活动的,它们不能被回收。因此,需要由程序负责从长期存活的映射表中删除那些无用的值。或者使用WeakHashMap完成这件事情。当对键的唯一引用来自散列条目时,这一数据结构将与垃圾回收器协同工作一起删除键/值对。
下面是这种机制的内部运行情况。WeakHashMap使用弱引用(weak references)保存键。WeakReference对象将引用保存到另外一个对象中,在这里,就是散列键。对于这种类型的对象,垃圾回收器用一种特有的方式进行处理。通常,如果垃圾回收器发现某个特定的对象已经没有他人引用了,就将其回收。然而,如果某个对象只能由 WeakReference引用,垃圾回收器仍然回收它,但要将引用这个对象的弱引用放人队列中。WeakHashMap将周期性地检查队列,以便找出新添加的弱引用。一个弱引用进人队列意味着这个键不再被他人使用,并且已经被收集起来。于是,WeakHashMap将删除对应的条目。
摘自Java核心技术 卷1(第十版)
WeakHashMap回收测试
1 @Test 2 public void Test3() { 3 String s1 = new String("s1"); 4 String s2 = new String("s2"); 5 String s3 = new String("s3"); 6 Map<String, Integer> map = new WeakHashMap<>(); 7 map.put(s1, 1); 8 map.put(s2, 2); 9 map.put(s3, 3); 10 map.forEach((K, V) -> System.out.println("GC回收前[" + K + ", " + V + "]")); 11 s2 = null; 12 System.gc(); 13 System.out.println(); 14 map.forEach((K, V) -> System.out.println("GC回收后[" + K + ", " + V + "]")); 15 }
输出结果:
GC回收前[s2, 2]
GC回收前[s1, 1]
GC回收前[s3, 3]
GC回收后[s1, 1]
GC回收后[s3, 3]
注意:如果Key为字面量时,WeakHashMap回收机制失效。
例如:
1 @Test 2 public void Test4() { 3 String s1 = "s1"; 4 String s2 = "s2"; 5 String s3 = "s3"; 6 Map<String, Integer> map = new WeakHashMap<>(); 7 map.put(s1, 1); 8 map.put(s2, 2); 9 map.put(s3, 3); 10 map.forEach((K, V) -> System.out.println("GC回收前[" + K + ", " + V + "]")); 11 s2 = null; 12 System.gc(); 13 System.out.println(); 14 map.forEach((K, V) -> System.out.println("GC回收后[" + K + ", " + V + "]")); 15 }
输出结果:
GC回收前[s2, 2]
GC回收前[s1, 1]
GC回收前[s3, 3]
GC回收后[s2, 2]
GC回收后[s1, 1]
GC回收后[s3, 3]
原文地址:https://www.cnblogs.com/mybdss/p/9160878.html