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
分享到:
相关推荐
5. WeakHashMap 的优点:WeakHashMap 可以自动地清除无用的缓存对象,从而避免了内存泄露,并且 WeakHashMap 可以在缓存中的对象变得无用时自动地将其清除。 6. WeakHashMap 的缺点:WeakHashMap 的键对象是弱引用...
WeakHashMap是Java中的一种特殊的哈希表实现,它使用弱引用(Weak Reference)来保存键对象。当键对象没有被其他强引用引用时,在垃圾回收时会自动从WeakHashMap中移除对应的键值对。
Java编程WeakHashMap实例解析 WeakHashMap是Java编程中的一种特殊的HashMap实现,它使用弱引用来保存键和值,这样可以使得垃圾回收器自动清理键和值。在WeakHashMap中,键和值都是弱引用的,这样可以避免内存泄露...
在《Effective Java 2nd Edition》中,第6条“消除过期的对象引用”提到,虽然Java有垃圾回收机制,但是只要是自己管理的内存,应该警惕内存泄露的问题,例如的对象池、缓存中的过期对象都有可能引发内存泄露的问题...
String key = entry.getKey(); Integer value = entry.getValue(); System.out.println(key + ": " + value); } ``` 或者,使用传统的迭代器: ```java Iterator, Integer>> it = map.entrySet().iterator(); ...
- **expungeStaleEntries 方法**:为了确保 WeakHashMap 的键被正确清理,每当访问 WeakHashMap 的时候,都会调用 expungeStaleEntries 方法来清除已经无效的键值对。 #### 七、WeakHashMap 的局限性 - **访问触发...
在Java编程中,WeakHashMap是一种特殊的哈希表,它的键(Key)是弱引用,当键被垃圾回收器清除后,即使有值(Value)存在,该条目也会自动从哈希表中移除。 线程死锁的原因通常包括以下几点: 1. **资源互斥**:每...
这意味着如果键不再被任何对象引用,那么即使在 WeakHashMap 中,这个键也会被垃圾收集器回收。这种方式可以防止内存泄漏,但也可能导致数据丢失。 总结: - Vector 和 ArrayList 都实现了 List 接口,其中 Vector ...
5. WeakHashMap:键使用弱引用,当键不再被引用时,键值对会被自动删除。 Map的遍历方式: 1. for-each循环:使用增强for循环遍历Map的entrySet()。 2. Iterator迭代器:通过Map的entrySet().iterator()获取迭代器...
Map接口是Java集合框架中的重要组成部分,它提供了一种存储键值对数据结构的方式,使得我们可以通过键(Key)快速查找对应的值(Value)。在Java中,有许多实现了Map接口的类,如HashMap、TreeMap、LinkedHashMap等...
而在Java中,Key/Value存储使用HashMap、TreeMap、WeakHashMap等类,例如:`HashMap,String> map = new HashMap();map.put("key","value");`。需要注意的是,在Java中,Key/Value存储需要提供hashCode函数和equals...
TreeMap则按照Key进行排序,而WeakHashMap使用弱引用键,有助于防止内存泄漏。 4. ConcurrentHashMap和Hashtable:ConcurrentHashMap是线程安全的Map,采用了分段锁策略,比Hashtable在多线程环境下表现更优。它在...
WeakHashMap是一种特殊的Map实现,它使用弱引用作为键,当键不再被引用时,即使在Map中,也会被垃圾回收器清除,从而释放内存资源。 总结来说,选择哪种容器取决于具体的需求:如果需要有序的元素集合,可以使用...
- **内存缓存**:Android应用中常见的内存缓存是使用`WeakHashMap`或者`LruCache`实现的内存对象缓存,它们存储在Dalvik/ART虚拟机的堆内存中。当内存不足时,系统会自动回收这些缓存。 - **外部存储缓存(外存)*...
Map接口则是用于存储键值对的集合,键(Key)必须是唯一的,而值(Value)可以重复。Map接口的实现类有Hashtable、HashMap、LinkedHashMap、WeakHashMap和IdentityHashMap。Hashtable与HashMap类似,但它是线程安全...
- **特点**:Map是一种键值对的数据结构,键(key)必须唯一,而值(value)可以重复。Map主要用于根据键来查找对应的值。 - **HashMap**:高效查找,基于哈希表,键和值都必须重写equals()和hashCode()。 - **...
例如,当缓存大量对象且不希望它们一直占用内存时,WeakIdentityHashMap可以确保一旦对象不再被使用,它们就会被自动清除。 【标签】"开源项目" 表明这些内容是开放源代码的,这意味着开发者可以自由地查看、使用、...
这意味着在多线程环境中,你可以直接使用`Hashtable`而不用担心数据同步问题。相反,`HashMap`实现了`Map`接口,它的方法默认是非同步的。在需要线程安全的情况下,可以使用`Collections.synchronizedMap(Map m)`...
WeakHashMap是Map接口的基于弱键的实现,以弱键实现的基于哈希表的Map。在WeakHashMap中,当某个键不再正常使用时,将自动移除其条目。 Java集合类提供了多种实现,用于解决不同的数据存储和操作问题。开发者可以...