有一个用例如 500 个条目初始化的 WeakHashMap 实例。现在,它的密钥在运行的应用程序中的任何地方都没有被引用一天左右。经过一定时间后,此地图的条目会自动删除吗?
我的理解是,如果未引用密钥,则将从地图中删除相应的条目。
有一个用例如 500 个条目初始化的 WeakHashMap 实例。现在,它的密钥在运行的应用程序中的任何地方都没有被引用一天左右。经过一定时间后,此地图的条目会自动删除吗?
我的理解是,如果未引用密钥,则将从地图中删除相应的条目。
如果您的密钥未在任何地方引用,它将在 GC 运行时被删除:(参考)
Map 接口的基于哈希表的实现,带有弱键。 WeakHashMap 中的条目在其键不再常用时将被自动删除。更准确地说,给定键的映射的存在不会阻止该键被垃圾收集器丢弃,也就是说,使其可终结,最终确定,然后回收。当一个键被丢弃时,它的条目被有效地从映射中删除,所以这个类的行为与其他映射实现有些不同。
移除时间未知:
WeakHashMap 中的每个键对象都间接存储为弱引用的所指对象。因此,只有在映射内部和外部的弱引用已被垃圾收集器清除后,才会自动删除键。
但要小心,一些对象,如 -127-> 127 等小整数的装箱整数被 JVM 缓存,因此如果您使用自动装箱整数键,它将永远不会从 Map 中删除。
经过一定时间后,此地图的条目会自动删除吗?
这取决于垃圾收集器何时到来。不能保证它甚至每天一次回收“垃圾”。
WeakHashMap
类的行为部分取决于垃圾收集器的行为,因此一些熟悉的(尽管不是必需的)Map
不变量不适用于此类。 因为垃圾收集器可能随时丢弃键,aWeakHashMap
可能表现得好像一个未知线程正在默默地删除条目。
好吧,首先我们缩小问题的范围。
问题:我们有一个WeakHashMap
我们有一些条目。如果这些条目未被使用,这些条目是否会被垃圾收集?
WeakHashMap<Object, Object> wkMap = new WeakHashMap<>()
Object obj1 = new Object();
Object obj2 = new Object();
Objcet obj1Meta = new Object();
Objcet obj2Meta = new Object();
wkMap.put(obj1, obj1Meta);
wkMap.put(obj2, obj2Meta);
首先,它与被使用无关,也与时间无关:它与对地图的引用(wkMap
在这种情况下)是否在范围内;如果没有,那么整个地图都有资格进行垃圾收集,这很简单。但如果不是,那么……
我们需要检查的一件事是映射键弱引用的对象是否已经被垃圾回收。在这种情况下obj1
和obj2
。
如果这些对象没有被垃圾回收,那么它们对应的条目将在地图中。垃圾收集器不会回收。再次直截了当。
obj1
现在棘手的情况是:被,弱引用的对象obj2
已被垃圾回收。地图中不需要它们的元数据wkMap
。理想情况下,它们应该被垃圾收集,最终它们是。但问题是如何...
obj1
,obj2
有资格进行垃圾回收wkMap
。ReferenceQueue
附加到它。如果有,那么 GC 会将弱引用放在 that 上ReferenceQueue
。GC 完成。null
. 等等,那是谁干的?我们接下来看看:手动清理是WeakHashMap
自己完成的。让我们检查一下size()
里面的代码WeakHashMap
:
public int size() {
if (size == 0)
return 0;
expungeStaleEntries();
return size;
}
专注于expungeStaleEntries()
;它也是从映射中删除所有条目的条目ReferenceQueue
,并且这些条目有资格进行垃圾收集(单个引用队列附加到用作映射中键的所有弱引用)。也检查expungeStaleEntries()
代码。
现在简而言之,如果您从您的代码中调用 上的某个方法,该方法在WeakHashMap
内部调用此expungeStaleEntries()
方法,那么只有这样条目才有资格进行垃圾回收。
expungeStaleEntries()
size()
reSize()
isEmpty()
putAll()
希望这能让事情变得清楚。
在这段代码中
WeakHashMap<Group,String> map = new WeakHashMap<>();
Group group1 = new Group();
Group group2 = new Group();
map.put(group1,"one");
map.put(group2,"two");
System.out.println(map);
group1 = null;
System.gc();
System.out.println(map);
在第一个 print 语句中,您将看到 hashmap 有两个元素,而在第二个 print 语句中它只有一个元素。因为对第一个元素的引用现在为空。所以是的,所有引用指向 null 的键都将在下次 GC 运行时被删除。
{Group@53e25b76=one, Group@73a8dfcc=two}//First print
{Group@73a8dfcc=two}//Second print