看Java源码的时候,看到了 WeakHashMap ,我一直以来使用的 都是 HashMap,于是查了一下两者的区别
(一) 查看API文档,WeakHashmap要点如下:
1. 以弱键 实现的基于哈希表的 Map。在 WeakHashMap 中,当某个键不再正常使用时,将自动移除其条目。更精确地说,对于一个给定的键,其映射的存在并不阻止垃圾回收器对该键的丢弃,这就使该键成为可终止的,被终止,然后被回收。丢弃某个键时,其条目从映射中有效地移除
2. WeakHashMap 类的行为部分取决于垃圾回收器的动作。因为垃圾回收器在任何时候都可能丢弃键,WeakHashMap 就像是一个被悄悄移除条目的未知线程。特别地,即使对 WeakHashMap 实例进行同步,并且没有调用任何赋值方法,在一段时间后 size 方法也可能返回较小的值,对于 isEmpty 方法,返回 false,然后返回true,对于给定的键,containsKey 方法返回 true 然后返回 false,对于给定的键,get 方法返回一个值,但接着返回 null,对于以前出现在映射中的键,put 方法返回 null,而 remove 方法返回 false,对于键 set、值 collection 和条目 set 进行的检查,生成的元素数量越来越少。
3. WeakHashMap 中的每个键对象间接地存储为一个弱引用的指示对象。因此,不管是在映射内还是在映射之外,只有在垃圾回收器清除某个键的弱引用之后,该键才会自动移除。
简而言之,WeakHashMap,此种Map的特点是,当除了自身有对key的引用外,此key没有其他引用那么此map会自动丢弃此值
Hashmap要点如下:
基于哈希表的 Map 接口的实现。此实现提供所有可选的映射操作,并允许使用 null 值和 null 键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。
(二) 示例演示
声明两个Map对象,一个是HashMap,一个是WeakHashMap,同时向两个map中放入a、b、c 三个对象,当HashMap remove掉a ,当WeakHashMap remove掉c,并且将a、b、c都指向null时,WeakHashMap中的a将自动被回收掉,HashMap中的c 依然存在。
出现这个状况的原因是,对于a对象而言,当HashMap remove掉并且将a指向null后,除了WeakHashMap中还保存a外已经没有指向a的指针了,所以WeakHashMap会自动舍弃掉a,而对于b对象虽然指向了null,但HashMap中还有指向b的指针,所以
WeakHashMap将会保留。
代码:
package com.panie.db.utils; import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.WeakHashMap; public class Test2
{
public static void main(String[] args)
{
String a = new String("a");
String b = new String("b");
String c = new String("c");
Map weakmap = new WeakHashMap();
Map map = new HashMap();
map.put(a, "aaa");
map.put(b, "bbb");
map.put(c, "ccc"); weakmap.put(a, "aaa");
weakmap.put(b, "bbb");
weakmap.put(c, "ccc");
map.remove(a);
weakmap.remove(c);
a=null;
b=null;
c=null; System.gc();
Iterator i = map.entrySet().iterator();
while (i.hasNext()) {
Map.Entry en = (Map.Entry)i.next();
System.out.println("map:"+en.getKey()+":"+en.getValue());
} Iterator j = weakmap.entrySet().iterator();
while (j.hasNext()) {
Map.Entry en = (Map.Entry)j.next();
System.out.println("weakmap:"+en.getKey()+":"+en.getValue()); }
}
}
结果:
map:b:bbb
map:c:ccc
weakmap:b:bbb
(三) 实际中的问题
在排查一个java heap溢出问题的时候,发现HashMap对象占用很多一直无法释放。
应用背景:读取一个大文件,每次读取处理10m数据,将数据放到HashMap中。
解决方式:尝试调用了map.clear();map=null;还告知System.gc()需要进行内存回收都没有办法,运行一段时间后heap中有大量HashMap对象无法回收。于是分析了下HashMap和WeakHashMap。采用WeakHashMap就可以了或者遍历hashmap把值都置为null。