WeakHashMap的回收机制分析

(转载)[https://www.ktanx.com/blog/p/288]

在Java中,一般人对于WeakHashMap的理解都是:当某个键不再被使用时,将自动移除回收其条目。

WeakHashMap真的是自动移除回收其条目的吗?

看了下WeakHashMap的实现源码,主要是通过expungeStaleEntries这个函数来实现回收的,基本上WeakHashMap中所有的public方法都调用了该函数,简言之就是只要访问WeakHashMap的内容就会调用该函数,从而达到清除其内部不再被引用的条目。

但是如果预先生成了WeakHashMap,而在gc以前又不曾访问该WeakHashMap,是不是就不能释放内存了呢? 写个代码测试一下:

List<WeakHashMap<byte[][], byte[][]>> maps = new ArrayList<WeakHashMap<byte[][], byte[][]>>();
for (int i = 0; i < 1000; i++) {
 WeakHashMap<byte[][], byte[][]> d = new WeakHashMap<byte[][], byte[][]>();
 d.put(new byte[5000][5000], new byte[5000][5000]);
 maps.add(d);
 System.gc();
 System.err.println(i);
}

在不改变JDK内存参数的情况下,该测试循环不了几次就内存溢出了,果不其然,WeakHashMap在这时候并没有自动帮我们清理不用的条目而释放内存。

加个会对map进行访问的代码试试:


List<WeakHashMap<byte[][], byte[][]>> maps = new ArrayList<WeakHashMap<byte[][], byte[][]>>();

for (int i = 0; i < 1000; i++) {

 WeakHashMap<byte[][], byte[][]> d = new WeakHashMap<byte[][], byte[][]>();

 d.put(new byte[1000][1000], new byte[1000][1000]);

 maps.add(d);

 System.gc();

 System.err.println(i);

 //元素并不存在,只达到访问WeakHashMap方法目的

 System.out.println(maps.get(0));

}

这下就没有问题了,测试顺利通过。

可见,WeakHashMap并不是你啥也不干就能自动清理回收内部对象的,而是在你访问它内容的时候释放内部不用的对象(实则是通过访问调用了它的expungeStaleEntries函数),没理解这一点,在程序中就有可能引发灾难!

在WeakHashMap$Entry<K,V>的构造函数里面是这样写的:

Entry(K key, V value, ReferenceQueue<K> queue, int hash, Entry<K, V> next) {

 super(key, queue);

 this.value = value;

 this.hash = hash;

 this.next = next;

}

注意它构造父类的语句:super(key, queue),传入的是key,因此key才是进行弱引用的,value是直接强引用关联在this.value之中,在System.gc()时,key被清除了,WeakHashMap本身根据ReferenceQueue中接收到的清除通知来清理value值,这个动作实现在expungeStaleEntries()方法之内,在getTable()之中对这个方法进行了调用,而WeakHashMap几乎在所有public的方法中都是要调用getTable()的。所以效果是key在GC的时候被清除,value在key清除后访问WeakHashMap的时候被清除。

WeakHashMap的说明之中也是说“An entry in a WeakHashMap will automatically be removed when its key is no longer in ordinary use”。所以WeakHashMap的实现并没有问题,只是人们大多想当然的理解为value会自动清除而已。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值