Java的弱引用—WeakHashMap
来源:互联网 发布:php use require 编辑:程序博客网 时间:2024/06/05 11:23
在《Effective Java》中的p23页有涉及到WeakHashMap
的相关知识,在这篇文章中做一个总结以及介绍一下相关知识。
在这里我们分成三个部分来说明一下,这只是我自己参看JDK源码和上网搜索资料得到的结果,如有错误,欢迎指出,我不胜荣幸。
WeakHashMap和HashMap有什么不同
我们知道WeakHashMap
是弱引用,而HashMap
是强引用。
这就是说当我们给Java虚拟机分配的内存不足的时候,HashMap
宁可抛出OutOfMemoryError
异常也不会回收其相应的没有被引用的对象,而我们的WeakHashMap
则会回收存储在其中但有被引用的对象。
如下的程序实例,运用的JVM参数为:-Xmx5m -Xms5m -XX:+PrintGC
HashMap
的测试代码
public static void main(String[] args) { HashMap hashMap = new HashMap(); for (int i = 0; ; i++) { hashMap.put(i, new String("HashMap"));//一直往里面加数据 if (i % 1000 == 0) { //每隔一千次判断一下有没有对象被回收 for (int j = 0; j < i; j++) {//遍历一遍 if (hashMap.get(j) == null) { System.out.println("第" + j + "个对象开始回收"); return; } } } } }
我们运行程序,发现没有任何对象被回收,最后抛出了异常
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.util.HashMap.addEntry(HashMap.java:753) at java.util.HashMap.put(HashMap.java:385)
那我们再来证明一下WeakHashMap
会回收其中存储的没有被引用的对象
public static void main(String[] args) { WeakHashMap hashMap = new WeakHashMap(); for (int i = 0; ; i++) { hashMap.put(i, new String("WeakHashMap"));//一直往里面加数据 if (i % 1000 == 0) { //每隔一千次判断一下有没有对象被回收 for (int j = 0; j < i; j++) {//遍历一遍 if (hashMap.get(j) == null) { System.out.println("第" + j + "个对象开始回收"); return; } } } } }
最后程序的输出如下
[GC 1408K->787K(4992K), 0.0067048 secs]第241个对象开始回收
可知WeakHashMap
将其中存储的键为241的对象开始回收了。
我们接下来思考,WeakHashMap
是怎样知道要回收对象的呢?
WeakHashMap
通过将一些没有被引用的键的值赋值为null
,这样的话就会告知GC去回收这些存储的值了。
那么也就是说,如果我们将其所有的键都添加引用,那么其就不会被回收了?我们来写一段代码测试一下
public static void main(String[] args) { WeakHashMap weakHashMap = new WeakHashMap(); HashMap hashMap=new HashMap(); for (int i = 0; ; i++) { Integer num=new Integer(i); hashMap.put(i,num); // num 被引用 weakHashMap.put(num, new String("WeakHashMap"));//将num改为i就会有对象被回收 if (i % 1000 == 0) { //每隔一千次判断一下有没有对象被回收 for (int j = 0; j < i; j++) {//遍历一遍 if (weakHashMap.get(j) == null) { System.out.println("第" + j + "个对象开始回收"); return; } } } } }
我们在HashMap
中存储了WeakHashMap
的键,这样就会是的其不会被回收,最后测试结果表示没有对象被回收,程序也就像我们期待的一下报了OutOfMemoryError
。
当然可能会有人说,为什么这个OutOfMemoryError
不是我们的HashMap
引起的呢,然后WeakHashMap
还没有达到回收的条件?
针对这一点,我根据程序中的注释将WeakHahMap
的键从num改为i,最后会发现有对象被回收。
既然WeakHashMap
是将我们的键值设置为null
从而引起GC的,那么我们将null
作为键存进去,为什么不会导致被回收呢?
这时候我们就需要看看其JDK的有关put
方法的源码了
public V put(K key, V value) { K k = (K) maskNull(key);// 重点看这里 int h = HashMap.hash(k.hashCode()); Entry[] tab = getTable(); int i = indexFor(h, tab.length); for (Entry<K,V> e = tab[i]; e != null; e = e.next) { if (h == e.hash && eq(k, e.get())) { V oldValue = e.value; if (value != oldValue) e.value = value; return oldValue; } } modCount++; Entry<K,V> e = tab[i]; tab[i] = new Entry<K,V>(k, value, queue, h, e); if (++size >= threshold) resize(tab.length * 2); return null; }
我们重点看一下开始的判断键时候为null
的maskNull()
方法。
private static Object maskNull(Object key) { return (key == null ? NULL_KEY : key); }
我们发现,如果key
是null
的话,返回的是NULL_KEY
这个静态值,我们再来看一下这个值是什么的时候,就恍然大悟了
/** * Value representing null keys inside tables. */ private static final Object NULL_KEY = new Object();
WeakHashMap
在存储null
为键的时候,其实存储的是其本身的静态成员变量Object
,也就是说存储的不是null
。
这也就解释了为什么存储键为null
不会被马上回收。
最后我们来看一下程序是在什么时候来判断要将没有引用的key
标记为null
的呢?
这时候WeakHashMap
中的一个非常重要的方法expungeStaleEntries()
就登场了。
在WeakHashMap
的put()
,get()
,remove()
等等方法中都调用了一个getTable()
方法,而这个getTable()
方法的源码如下:
private Entry[] getTable() { expungeStaleEntries(); return table; }
可以知道他们其实调用的都是expungeStaleEntries()
方法。
可知这个方法是一个非常重要的方法。
[注].出自: Java集合框架:WeakHashMap,一篇非常优秀的博客!
首先我们看一下其实现的源码
/** * Expunges stale entries from the table. */ private void expungeStaleEntries() { Entry<K,V> e; while ( (e = (Entry<K,V>) queue.poll()) != null) { int h = e.hash; int i = indexFor(h, table.length); Entry<K,V> prev = table[i]; Entry<K,V> p = prev; while (p != null) { Entry<K,V> next = p.next; if (p == e) { if (prev == e) table[i] = next; else prev.next = next; e.next = null; // Help GC e.value = null; // " " size--; break; } prev = p; p = next; } } }
可以看到每调用一次expungeStaleEntries()
方法,就会在引用队列中寻找是否有将要被清除的key
对象,如果有则在table中找到其值,并将value
设置为null
,next
指针也设置为null
,让GC去回收这些资源。
2017-11-18 15:23 于上海
- Java的弱引用—WeakHashMap
- Java弱引用与WeakHashMap的介绍
- Java弱引用与WeakHashMap
- Java弱引用与WeakHashMap
- Java弱引用与WeakHashMap
- java 引用的SoftReference,WeakReference&WeakHashMap
- java 弱引用集合类WeakHashMap
- Java弱引用与WeakHashMap(转)
- Java引用&WeakHashMap
- java的WeakHashMap详细介绍
- java WeakHashMap
- Java WeakHashMap
- java中WeakHashMap的个人理解
- java集合第八章WeakHashMap的用法
- Java WeakHashMap使用陷阱
- Java :map、WeakHashMap、IdentityHashMap
- java WeakHashMap 使用
- java WeakHashMap 原理
- Python (注释多行输出,浮点整数)
- 解决javaWEB中前后台中文乱码问题
- 内核编译流程
- 随笔-NOIP完结后的回首(未完,想补再写)
- java编程规范
- Java的弱引用—WeakHashMap
- Java面试遇到的问题总结(一)
- 测试项目管理
- Linux平台彻底卸载MySQL总结
- 第一章习题
- 在Linux中让echo命令显示带颜色的字
- Java,Python,Scala比较(三)wordcount
- day-13
- 比特币区块结构Merkle树及简单支付验证分析