WeakHashMap实现了Map接口,是HashMap的一种实现,他使用弱引用作为内部数据的存储方案,WeakHashMap可以作为简单缓存表的解决方案,当系统内存不够的时候,垃圾收集器会自动的清除没有在其他任何地方被引用的键值对。
如果需要用一张很大的HashMap作为缓存表,那么可以考虑使用WeakHashMap,当键值不存在的时候添加到表中,存在即取出其值。
WeakHashMap weakMap = new WeakHashMap<Integer, byte[]>(); for(int i = 0; i < 10000; i++){ Integer ii = new Integer(i); weakMap.put(ii, new byte[i]); }
HashMap map = new HashMap<Integer, byte[]>(); for (int i = 0; i < 10000; i++) { Integer ii = new Integer(i); map.put(ii, new byte[i]); }
这2段代码分别用-Xmx5M的参数运行,运行的结果是第一段代码可以很好的运行,第二段代码会出现“Java Heap Space”的错误,这说明用WeakHashMap存储,在系统内存不够用的时候会自动回收内存。
如果WeakHashMap的key在系统内持有强引用,那么WeakHashMap就退化为HashMap,所有的表项无法被垃圾收集器自动清理。
1 package com.froest.excel; 2 3 import java.util.Iterator; 4 import java.util.Map; 5 import java.util.WeakHashMap; 6 7 public class Test5 { 8 9 /** 10 * @param args 11 */ 12 public static void main(String[] args) { 13 // TODO Auto-generated method stub 14 WeakHashMap<AA, People1> weakMap1 = new WeakHashMap<AA, People1>(); 15 String b = new String("louhang1"); 16 AA a = new AA(b); 17 BB bb = new BB(a); 18 People1 p1 = new People1(bb); 19 weakMap1.put(p1.getB().getAA(), p1); 20 p1.getB().setAA(null);// 去除对象a的强引用 21 a = null;// 去除对象a的强引用,并让垃圾收集器回收AA对象在堆中的内存 22 System.gc(); 23 Iterator i = weakMap1.entrySet().iterator(); 24 while (i.hasNext()) { 25 Map.Entry en = (Map.Entry) i.next(); 26 System.out.println("weakMap:" + en.getKey() + ":" + en.getValue()); 27 } 28 } 29 } 30 31 class AA { 32 private String a; 33 34 public AA(String a) { 35 this.a = a; 36 } 37 38 public String getA() { 39 return a; 40 } 41 42 public void setA(String a) { 43 this.a = a; 44 } 45 } 46 47 class BB { 48 private AA a; 49 50 public BB(AA a) { 51 this.a = a; 52 } 53 54 public AA getAA() { 55 return a; 56 } 57 58 public void setAA(AA a) { 59 this.a = a; 60 } 61 } 62 63 class People1 { 64 private BB b; 65 66 public People1(BB b) { 67 this.b = b; 68 } 69 70 public BB getB() { 71 return b; 72 } 73 74 public void setB(BB b) { 75 this.b = b; 76 } 77 }
View Code
运行上面代码以后没有输出任何结果,说明,WeakHashMap中的键值对已经被回收了,如果注释掉p1.getB().setAA(null);或者a = null;这2行中的任意一行都没法清除WeakhashMap中的键值对。
在WeakHashMap的get(),put()函数中的getTable()方法会调用expungeStateEntries方法,以清理持有弱引用的key的表项。exPungeStateEntries方法源代码:
1 private void expungeStaleEntries() { 2 Entry<K,V> e; 3 while ( (e = (Entry<K,V>) queue.poll()) != null) { 4 int h = e.hash; 5 int i = indexFor(h, table.length); 6 7 Entry<K,V> prev = table[i]; 8 Entry<K,V> p = prev; 9 while (p != null) { 10 Entry<K,V> next = p.next; 11 if (p == e) { 12 if (prev == e) 13 table[i] = next; 14 else 15 prev.next = next; 16 e.next = null; // Help GC 17 e.value = null; // " " 18 size--; 19 break; 20 } 21 prev = p; 22 p = next; 23 } 24 } 25 }
View Code
在第二个while循环中会移除已经被回收的表项。