【问题标题】:In weakHashMap if i update or change the previously stored key object, the garbage Collector deletes the key value pair在weakHashMap中,如果我更新或更改之前存储的键对象,垃圾收集器会删除键值对
【发布时间】:2020-02-19 13:01:10
【问题描述】:

我在WeakHashMap 中存储了一个对象作为键。现在,如果我更改它的值,然后调用 GC 并打印 map,那么什么都没有。

public static void main(String[] args) throws InterruptedException{

    WeakHashMap map = new WeakHashMap();
    Integer obj = new Integer(200);
    map.put(obj, "sgdjsgd");
    obj=new Integer(20);
    System.gc();
    Thread.sleep(2000);
    System.out.println(map);
}
  • 预期输出:{200,"sgdjsgd"}
  • 实际输出:{}

【问题讨论】:

  • 是什么让您如此期待? 给定键的映射不会阻止垃圾收集器丢弃该键 (WeakHashMap documentation)
  • 顺便说一句don’t use raw types。并且 Integer 构造函数已被弃用,而是使用 Integer.valueOf(200) 等。
  • 它完全按照设计工作。您已经丢弃了对密钥的引用;它只保留对密钥的弱引用;因此,当您执行 get() 键时,该值可能已被垃圾收集。
  • 当您期望输出{200,"sgdjsgd"} 时,您已经承认地图与包含20obj 变量之间没有关系。那么,为什么您希望 obj 变量持有对 20 的引用来阻止收集 200 键?

标签: java garbage-collection weakhashmap


【解决方案1】:

user207421 说得非常准确:您的代码完全按照设计工作。我不清楚你是如何期待其他东西的,但我想指出:

  • 您的代码不会改变地图内的任何内容。将新值 20 分配给 obj 只会更改该变量。地图中的键仍然是 Integer,其值为 200。
  • 将 20 分配给 obj 确保映射中没有其他对键 200 的引用,这就是允许垃圾收集器从映射中删除该键的原因。

如果您想更改地图中的键:永远不要。哈希映射,包括WeakHashMap,通过哈希码存储对象。更改密钥对象很可能会更改哈希码。所以地图将无法再次找到钥匙,即使它在那里。如果您需要此功能,您必须先从地图中移除密钥,然后再插入新密钥:

    String value = map.remove(obj);
    obj = Integer.valueOf(20);
    map.put(obj, value);

通过对您的代码进行此更改,我得到以下输出:

{20=sgdjsgd}

【讨论】:

    【解决方案2】:

    WeakHashMap 可能表现得好像一个未知线程正在默默地删除条目。

    WeakHashMap.Entry 是一个WeakReference 对象,其引用对象是您传递给map.put()key 对象。也就是说如果key变成weakly reachable,垃圾收集器会自动声明它为finalizable。

    Java SE 8 文档说 that:

    一个对象是弱可达的,如果它既不是强可达也不是软可达,但可以通过遍历弱引用到达。当对弱可达对象的弱引用被清除后,该对象就可以被终结。

    在这行代码中

        Integer obj = new Integer(200);
        map.put(obj, "sgdjsgd");
    

    obj 是对new Integer(200) 创建的整数对象的强引用,然后将其传递给map.put(),后者会创建一个WeakReference(假设它被称为w)来保存这个整数对象。

    但是在这一行之后:

    obj = new Integer(20);
    

    obj 指向另一个包含 20 的整数对象w 仍然指向包含 200 的整数对象)。 但是更改obj指向的对象会使w的所指对象变为weakly reachable,因为它只能通过遍历弱引用(即w)来达到。

    当控制从方法调用返回到System.gc() 时,JVM 已尽最大努力回收所有丢弃的对象。所以如上所述,垃圾收集器会原子地声明弱可达对象可终结并最终清除它们。

    所以w 被清除,映射中的条目被垃圾收集器丢弃,结果,您的映射不包含任何内容。

    【讨论】:

    • 让我们一步一步来:先obj->200,然后当我们写map.put(obj, "sgdjsgd"); weakRef->obj->200 那么我们改变 obj->20 那么它应该是weakRef->obj->20 ryt?
    • 不,@sonukumar。 obj=new Integer(20); 将一个新对象分配给obj,但不会更改地图内的任何内容。所以此时地图(可能)仍然是{200,"sgdjsgd"}
    【解决方案3】:

    我不确定您要做什么,但我在您的代码中看到的是,您将一个新对象分配给以前指向 WeakHashMap 中的键的引用,通过这样做,原始键(整数(200)) 没有指针,所以它没用,因为你永远无法到达那个键,所以 gc 会处理它是合乎逻辑的

    【讨论】:

      【解决方案4】:

      使用此代码,您正在更改存储在obj 中的内存中的指针:

      obj=new Integer(20);
      

      在这一行之前,obj 持有指向 new Integer(200); 的指针引用

      现在,obj 持有指向 new Integer(20); 的指针引用,这与内存中的先前不同。

      因此,因为WeakHashMap持有弱引用,当垃圾收集器运行时它会收集映射所引用的对象,所以当你打印映射时它显示{},因为保存在映射键中的指针不再存在找到了。

      【讨论】:

      • 让我们一步一步来:先obj->200,然后当我们写map.put(obj, "sgdjsgd"); weakRef->obj->200 那么我们改变 obj->20 那么它应该是weakRef->obj->20 ryt?
      【解决方案5】:
      Integer obj = new Integer(200);
      

      这会默认创建一个对 Integer 对象的强引用 obj ----强引用---->200

      map.put(obj, "sgdjsgd");
      

      obj ----弱引用 ----->200
      现在整数对象 200 具有强引用和弱引用,因此它不符合 GC 条件

      obj=new Integer(20);
      

      obj ----强引用---->20

      obj-----X----->200 obj ----弱引用--->200

      这里已经丢失了对 200 的现有强引用。所以整数对象 200 只剩下弱引用,会被 GC 急切地回收。

      因此,key 也会从 weakHashMap 中删除

      查看此链接了解更多详情 http://www.fis.unipr.it/lca/tutorial/java/refobjs/about/weak.html

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-12
        • 1970-01-01
        • 2019-02-26
        • 1970-01-01
        • 1970-01-01
        • 2020-10-21
        相关资源
        最近更新 更多