6

WeakHashMap 是 Map 接口的一个实现,如果相应的键不再被程序的任何部分引用,则 Grabage Collector 可以回收值对象的内存。因此,如果程序中不再使用密钥。无论其用途如何,它的 Entry 对象都将被垃圾回收。到这里为止很清楚

这与 HashMap 不同,其中值对象保留在 HashMap 中,即使不再引用 key。我们需要在 HashMap 对象上显式调用 remove() 方法来删​​除该值。调用 remove 只会从地图中删除条目。它对 GC 的准备情况将取决于它是否仍在程序中的某个地方使用。

请找到上面解释的这个编码示例

根据我的理解,在 HashMap 上使用 Wea​​kHashMap

我的理解是,只有当我们想要确保在程序的任何部分不再引用键时,Grabage Collector 回收值对象时,我们才应该使用 Wea​​kHashMap。这使程序内存高效我的理解在这里正确吗?

根据JavaDocs使用 Wea​​kHashMap ,我可以发现这个语句

此类主要用于关键对象,其 equals 方法使用 == 运算符测试对象身份。

我没有明白上述陈述的含义以及它与我对 WeakHashMap 用法的理解有何不同。实际上我没有明白这个声明与 WeakHashMap 的使用有什么关系?

更新:- 在进一步仔细阅读下面的声明 javadocs

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

为了我和他人的利益,我正在修改我的理解

根据我修改后的理解,在 HashMap 上使用 Wea​​kHashMap

仅当我们想要确保在 GC 运行时从 map 中删除键值对时,我们才应该使用 Wea​​kHashMap,此时键不再被普通使用,而不是 map 本身。

例子是:-

    WeakHashMap<Integer, String> numbers = new WeakHashMap<Integer, String>();
    numbers.put(new Integer(1), "one");// key only used within map not anywhere else
    numbers.put(new Integer(2), "two");
    System.out.println(numbers.get(new Integer(1))); // prints "one"
    System.gc();
    // let's say a garbage collection happens here
    System.out.println(numbers.get(new Integer(1))); // prints "null"
    System.out.println(numbers.get(new Integer(2))); // prints "null"


    Object key = new Object();
    m1.put(key, c1);
    System.out.println(m1.size());
    key = null or new Object() ; // privious key only used within map not anywhere else
    System.gc();
    Thread.sleep(100);
    System.out.println(m1.size());
4

5 回答 5

2

这是因为当对象不再具有来自程序的任何其他部分的强引用时,它们将被垃圾收集(GCed)。

给定一个WeakHashMap<MyObject, String>then 如果我们执行以下操作:

MyObject mo = new MyObject();
map.put(mo, "Test");
mo = null;

然后该条目mo -> Test将有资格获得 GC。这意味着,如果您有一个自定义.equals实现,它使用 的某些属性MyObject来测试是否相等,那么您以后不能这样做:

MyObject mo2 = new MyObject();
map.get(mo2);

因为即使您覆盖的.equals方法可能会说mo2.equals(mo) == true情况并非如此,mo2 == mo因此该条目可能已经被 GCed。

关键是,如果您保留对 的引用mo并使用它从 中检索值,Map那么该引用必须是这种情况,== mo因此有两件事是正确的:

  1. 该条目mo -> Test不能被 gced
  2. 您可以使用==基于.equals方法从地图中检索条目

基本上; 由于 GC 将使用强引用来测试对象是否可以被 GC,因此最好确保您的.equals方法也这样做以避免混淆。

于 2013-12-23T12:01:20.003 回答
1

该文档意味着此代码不是很有用:

WeakHashMap<Integer, String> numbers = new WeakHashMap<Integer, String>();
numbers.put(new Integer(1), "one");
numbers.put(new Integer(2), "two");
System.out.println(numbers.get(new Integer(1))); // prints "one"
// let's say a garbage collection happens here
System.out.println(numbers.get(new Integer(1))); // prints "null"
System.out.println(numbers.get(new Integer(2))); // prints "null"

对于不同实例可以相等的任何类都会发生这种情况。javadoc 只是警告您,如果您还没有注意到,这没有帮助。

于 2013-12-23T11:59:41.410 回答
1

运行此测试

    Object key = new Object();
    WeakHashMap m = new WeakHashMap();
    m.put(key, 1);
    System.out.println(m.size());
    key = null;
    System.gc();
    Thread.sleep(100);
    System.out.println(m.size());

虽然 System.gc 不保证运行 GC,但在我的 Oracle 的 JVM 7 上它总是运行并且这个测试打印

1
0

这意味着 GC 从 map 中删除了该条目,因为 key 不是从任何地方引用的,而是 map 本身

于 2013-12-23T12:04:06.963 回答
0

我认为这意味着相等的对象测试使用内存中的对象位置,而不仅仅是因为两个不同的实例碰巧在它们的值上“相等”。

如果不是这种情况,则很难判断该键是否被更多引用以及不同但“相等”的值,实例可能被引用并用于查找该值。

如果它说键必须具有引用相等性,以便您知道键何时不再被 WeakHashMap 实例以外的任何其他对象引用,则可能会更清楚

于 2013-12-23T11:54:24.863 回答
0

基于 Evgeniy Dorofeev 的回答,这里有一个带有一些陷阱的例子:

import java.util.Map;
import java.util.WeakHashMap;

public class WeakHashMapTest {

    public static void main(String[] args) throws InterruptedException {
        String key = new String();
        Map<String, String> m = new WeakHashMap();

        m.put(key, "value");
        System.out.println(m.size());

        m.put("key", "value");
        System.out.println(m.size());

        m.put(new String(), "value");
        System.out.println(m.size());

        m.put(new String("k"), "value");
        System.out.println(m.size());

        key = null;
        System.gc();
        Thread.sleep(100);

        System.out.println(m.size());
    }
}

输出

1
2
2
3
1
于 2017-07-19T08:39:13.967 回答