如果需要用一张很大的HashMap作为缓存表,那么可以考虑使用WeakHashMap,当键值不存在的时候添加到表中,存在即取出其值。
1
2
3
4
5
|
WeakHashMap weakMap = new WeakHashMap<Integer, byte []>();
for ( int i = 0 ; i < 10000 ; i++){
Integer ii = new Integer(i);
weakMap.put(ii, new byte [i]);
}
|
1
2
3
4
5
|
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 }
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 }
运行上面代码以后没有输出任何结果,说明,WeakHashMap中的键值对已经被回收了,如果注释掉p1.getB().setAA(null);或者a = null;这2行中的任意一行都没法清除WeakhashMap中的键值对。
在WeakHashMap的get(),put()函数中的getTable()方法会调用expungeStateEntries方法,以清理持有弱引用的key的表项。exPungeStateEntries方法源代码:
7 Entry<K,V> prev = table[i];
15 prev.next = next;
17 e.value = null; // " "
18 size--;
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 }
在第二个while循环中会移除已经被回收的表项。