3

有一个用例如 500 个条目初始化的 WeakHashMap 实例。现在,它的密钥在运行的应用程序中的任何地方都没有被引用一天左右。经过一定时间后,此地图的条目会自动删除吗?

我的理解是,如果未引用密钥,则将从地图中删除相应的条目。

4

4 回答 4

3

如果您的密钥未在任何地方引用,它将在 GC 运行时被删除:(参考

Map 接口的基于哈希表的实现,带有弱键。 WeakHashMap 中的条目在其键不再常用时将被自动删除。更准确地说,给定键的映射的存在不会阻止该键被垃圾收集器丢弃,也就是说,使其可终结,最终确定,然后回收。当一个键被丢弃时,它的条目被有效地从映射中删除,所以这个类的行为与其他映射实现有些不同。

移除时间未知:

WeakHashMap 中的每个键对象都间接存储为弱引用的所指对象。因此,只有在映射内部和外部的弱引用已被垃圾收集器清除后,才会自动删除键。

但要小心,一些对象,如 -127-> 127 等小整数的装箱整数被 JVM 缓存,因此如果您使用自动装箱整数键,它将永远不会从 Map 中删除。

于 2018-05-19T07:04:04.613 回答
2

经过一定时间后,此地图的条目会自动删除吗?

这取决于垃圾收集器何时到来。不能保证它甚至每天一次回收“垃圾”。

WeakHashMap类的行为部分取决于垃圾收集器的行为,因此一些熟悉的(尽管不是必需的)Map不变量不适用于此类。 因为垃圾收集器可能随时丢弃键,aWeakHashMap可能表现得好像一个未知线程正在默默地删除条目。

JDK 10 -WeakHashMap

于 2018-05-19T07:08:57.053 回答
2

好吧,首先我们缩小问题的范围。

问题:我们有一个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在这种情况下)是否在范围内;如果没有,那么整个地图都有资格进行垃圾收集,这很简单。但如果不是,那么……

我们需要检查的一件事是映射键弱引用的对象是否已经被垃圾回收。在这种情况下obj1obj2

如果这些对象没有被垃圾回收,那么它们对应的条目将在地图中。垃圾收集器不会回收。再次直截了当。

obj1现在棘手的情况是:被,弱引用的对象obj2已被垃圾回收。地图中不需要它们的元数据wkMap。理想情况下,它们应该被垃圾收集,最终它们是。但问题是如何...

一步步

  1. 被 弱引用的对象obj1,obj2有资格进行垃圾回收
  2. 垃圾收集器收集对象;此时,垃圾收集器检查是否存在对其正在收集的对象的任何弱引用。在我们的例子中,我们有两个:weak hash map 中两个条目的键wkMap
  3. 如果 GC 发现对它正在收集的对象的一些弱引用,它会检查这些引用是否有任何ReferenceQueue附加到它。如果有,那么 GC 会将弱引用放在 that 上ReferenceQueue。GC 完成。
  4. 到目前为止,这些条目都在地图中,它们不符合垃圾收集的条件。它会一直存在于地图中,直到有人手动将键设置为null. 等等,那是谁干的?我们接下来看看:
  5. 手动清理是WeakHashMap自己完成的。让我们检查一下size()里面的代码WeakHashMap

    public int size() {
        if (size == 0)
            return 0;
        expungeStaleEntries();
        return size;
    }
    

    专注于expungeStaleEntries();它也是从映射中删除所有条目的条目ReferenceQueue,并且这些条目有资格进行垃圾收集(单个引用队列附加到用作映射中键的所有弱引用)。也检查expungeStaleEntries()代码。

现在简而言之,如果您从您的代码中调用 上的某个方法,该方法在WeakHashMap内部调用此expungeStaleEntries()方法,那么只有这样条目才有资格进行垃圾回收

调用的方法列表expungeStaleEntries()

  • size()
  • reSize()
  • isEmpty()
  • putAll()
  • ETC...

希望这能让事情变得清楚。

于 2018-06-19T12:41:52.903 回答
0

在这段代码中

 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
于 2018-05-19T07:16:06.843 回答