`

WeakHashMap是如何清除不用的key的

阅读更多

WeakHashMap 是主要通过 expungeStaleEntries 这个函数的来实现移除其内部不用的条目从而达到的自动释放内存的目的的 . 基本上只要对 WeakHashMap 的内容进行访问就会调用这个函数,从而达到清除其内部不在为外部引用的条目。但是如果预先生成了 WeakHashMap ,而在 GC 以前又不曾访问该 WeakHashMap, 那不是就不能释放内存了吗?

对应的两个测试案例 :

WeakHashMapTest1 :

public class WeakHashMapTest1 {
public static void main(String[] args) throws Exception {
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

);
}
}
}

  

由于 Java 默认内存是 64M ,所以再不改变内存参数的情况下,该测试跑不了几步循环就内存溢出了。果不其然, WeakHashMap 这个时候并没有自动帮我们释放不用的内存。

WeakHashMapTest2 :

public class WeakHashMapTest2 {
    public static void main(String[] args) throws Exception {
        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

);
            for (int j = 0;

 j <

 i

; j++) {
                System.err

.println

(j + " size" + maps.get

(j).size

());
            }
        }
    }
} 

这次测试输出正常 , 不在出现内存溢出问题 .

总结来说: WeakHashMap 并不是你啥也干他就能自动释放内部不用的对象的,而是在你访问它的内容的时候释放内部不用的对象

问题讲清楚了 , 现在我们来梳理一下 . 了解清楚其中的奥秘 .

WeakHashMap 实现弱引用,是因为它的 Entry<K,V> 是继承自 WeakReference<K>

WeakHashMap$Entry<K,V> 的类定义及构造函数里面是这样写的

private static class Entry<

K,V>

 
    extends WeakReference<

K>

 
    implements Map.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 中的 byte 数组进行了回收 , value 依然保持 (value 被强关联到 entry ,entry 又关联在 map ,map 关联在 arrayList .).

如何证明 key 中的 byte 被回收了呢 ? 可以通过内存溢出时导出的内存镜像进行分析 , 也可以通过如下的小测试得出结论 :

把上面的value用小对象代替,

for (int i

 = 0;

 i

 <

 10000;

 i

++) { 
    WeakHashMap<

byte[][], Object>

 d = new WeakHashMap<

byte[][], Object>

(); 
    d.put

(new byte[1000][1000], new Object()); 
    maps.add

(d); System.gc

(); 
    System.err

.println

(i

); 
} 

上面的代码,即使执行10000次也没有问题,证明key中的byte数组确实被回收了。

for 循环中每次都new一个新的WeakHashMap,在put操作后,虽然GC将WeakReference的key中的byte数组回收了,并将事件通 知到了ReferenceQueue,但后续却没有相应的动作去触发 WeakHashMap 去处理 ReferenceQueue

所以 WeakReference 包装的key依然存在在WeakHashMap中,其对应的value也当然存在。

  value 是何时被清除的呢 ?

对两个例子进行分析可知 , 例子二中的maps.get(j).size()触发了 value 的回收 , 那又如何触发的呢 . 查看 WeakHashMap 源码可知 ,size 方法调用了 expungeStaleEntries方法 , 该方法对 vm 要回收的的 entry(quene ) 进行遍历 , 并将 entry value 置空 , 回收了内存 .

所以效果是 key GC 的时候被清除 ,value key 清除后访问 WeakHashMap 被清除 .

疑问 :key quene map quene 是同一个 quene,poll 操作会减少一个 reference, 那问题是 key 如果先被清除 , expungeStaleEntries遍历 quene 时那个被回收的 key 对应的 entry 还能取出来么 ???

关于执行 Sys tem.GC ,key 中的 byte 数据如何被回收了 , 请见 WeakReference referenceQuene

分享到:
评论

相关推荐

    java集合-WeakHashMap的使用

    WeakHashMap是Java中的一种特殊的哈希表实现,它使用弱引用(Weak Reference)来保存键对象。当键对象没有被其他强引用引用时,在垃圾回收时会自动从WeakHashMap中移除对应的键值对。

    WeakHashMap的使用方法详解

    主要介绍了WeakHashMap的使用方法详解的相关资料,希望通过本文能帮助到大家,让大家理解掌握这部分内容,需要的朋友可以参考下

    解析WeakHashMap与HashMap的区别详解

    本篇文章是对WeakHashMap与HashMap的区别进行了详细的分析介绍,需要的朋友参考下

    Java编程WeakHashMap实例解析

    主要介绍了Java编程WeakHashMap实例解析,分享了相关代码示例,小编觉得还是挺不错的,具有一定借鉴价值,需要的朋友可以参考下

    Java弱引用与WeakHashMap

    在《Effective Java 2nd Edition》中,第6条“消除过期的对象引用”提到,虽然Java有垃圾回收机制,但是只要是自己管理的内存,应该警惕内存泄露的问题,例如的对象池、缓存中的过期对象都有可能引发内存泄露的问题...

    Java期末复习-类集框架

    SortedMap接口、HashMap类、Hashtable类、Properties类、Map.Entry接口、WeakHashMap类、IndentityHashMap类 集合输出: Iterator、ListIterator、foreach、废除的Enumeration Collections工具类 Comparable接口、...

    线程死锁CPU过高,请求原因分析

    线程死锁 CPU过高 WeakHashMap 请求原因分析

    WeakObjectPool:用于在对象生命周期中将对象附加到对象(即装饰器)的池

    这里有几个关键的区别,它们有效地定义了WeakObjectPool: WeakHashMap具有弱键而不是值,例如WeakObjectPool。 它是一个池而不是一个地图,否则也称为多地图。 WeakObjectPool允许您在对象(装饰器)的生命周期...

    Java 基础核心总结 +经典算法大全.rar

    Hashtable 类IdentityHashMap 类WeakHashMap 类 Collections 类集合实现类特征图 泛形 泛型的使用 用泛型表示类 用泛型表示接口泛型方法 泛型通配符 反射 Class 类Field 类Method 类ClassLoader 类 枚举 枚举特性 ...

    picketlink-jbas-common-2.6.0.CR4.zip

    Java-WeakIdentityHashMap.zip,weakhashmap identityhashmapa独立库的组合,用于weakidantityhashmap实现内/外字段

    Java集合类操作优化经验总结

    本文首先针对 Java 集合接口进行了一些介绍,并对这些接口的实现类进行详细描述,包括 LinkedList、ArrayList、Vector、Stack、Hashtable、HashMap、WeakHashMap 等,然后对一些实现类的实现方式和使用经验进行讲解...

    各种集合的总结

    总结了集合中常用的一点点,希望可以共享 List:LinkedList,ArrayList,Vector(Stack),Set Map:Hashtable,HashMap,WeakHashMap

    清华妹子的Java仓库(进阶学习路线)

    本仓库记录了我的Java学习进阶之路,涵盖了Java基础、JDK源码、JVM中的重要知识,附有代码和博客讲解,旨在提供一个Java在线共享学习平台,帮助更多的...Java集合框架源码解读(4)——WeakHashMap Java集合框架源码解读

    java集合框架 解析

    java集合框架 3.6. LinkedHashSet类 4. Map接口 4.1. Map.Entry接口 4.2. SortedMap接口 4.3. AbstractMap抽象类 4.4. HashMap类和TreeMap类 4.4.1. HashMap类 ...4.6. WeakHashMap类 4.6. IdentityHashMap类

    超全Java集合框架讲解.md

    - WeakHashMap - Hashtable - Collection 集合体系详解 - Set 接口 - AbstractSet 抽象类 - SortedSet 接口 - HashSet - LinkedHashSet - TreeSet - List 接口 - AbstractList 和 AbstractSequentialList...

    javabitset源码-JerrySoundCode:杰瑞声码

    WeakHashMap (done) 并发集合 ArrayBlockingQueue(done) LinkedBlockingDeque (done) LinkedBlockingQueue (done) PriorityBlockingQueue (done) ConcurrentHashMap (done) ConcurrentLinkedQueue (done) C

    疯狂JAVA讲义

    7.6.3 WeakHashMap实现类 279 7.6.4 IdentityHashMap实现类 280 7.6.5 EnumMap实现类 281 7.7 HashSet和HashMap的性能选项 282 7.8 操作集合的工具类:Collections 283 7.8.1 排序操作 283 7.8.2 查找,替换...

    javalruleetcode-dsal:数据结构与算法个人整理

    java lru leetcode 基础算法 快速排序: 随机枢纽元快排、三路快排、三数中值快排 归并排序: 自顶向下归并、自底向上...WeakHashMap Leetcode 刷题记录 栈实现队列、队列实现栈、猫狗队列、带有最小值的栈、LRU、数据

    Java优化编程(第2版)

    15.1 用weakhashmap屏蔽内存泄漏 15.2 优化java应用大小 15.3 通过randomaccess接口优化迭代列表 15.4 合并java中的多进程与系统优化 小结 附录a together工具的使用简介 附录b j2se 5.0的新特性与性能的提升 附录c ...

    Thinking in Java 4th Edition

    What’s Inside Preface 1 Java SE5 and SE6 .................. 2 Java SE6 ............................................The 4th edition...........................Changes ...........................................

Global site tag (gtag.js) - Google Analytics