Java WeakHashMap类

4

我想测试Java WeakHashMap类的功能,为此我编写了以下测试:

public class WeakHashMapTest {

public static void main(String args[]) {
    Map<String, Object> weakMap = new WeakHashMap<>();
    String x = new String("x");     
    String x1 = new String("x1");   
    String x2 = new String("x2");   
    weakMap.put(x, x);
    weakMap.put(x1, x1);
    weakMap.put(x2, x2);
    System.out.println("Map size :" + weakMap.size());
    // force all keys be eligible
    x=x1=x2=null;
    // call garbage collector 
    System.gc();
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    System.out.println("Map size :" + weakMap.size());
    System.out.println("Map :" + weakMap);
}

}    

在运行WeakMapTest类之后,我惊讶地发现输出如下:
垃圾回收前的映射:{x=x,x1=x1,x2=x2} 垃圾回收后的映射:{x=x,x1=x1,x2=x2}
我本以为这个映射将为空。
也就是说,垃圾回收器没有起作用。但是为什么呢?
2个回答

5
WeakHashMap 是一种可以自动回收键的垃圾收集器的数据结构。当键不再具有强引用时,垃圾收集器会将其回收。 实现注意事项: WeakHashMap 中的值对象是由普通强引用保持的,因此应该注意确保值对象不会直接或间接地强引用自己的键,否则就会防止键被丢弃。
但是,如果您使用键本身作为值,则该值仍然具有强引用,这意味着垃圾收集器无法回收键。
然而,如果您使用其他对象作为值,则对键的唯一引用将是键本身。
weakMap.put(x, new Object());
weakMap.put(x1, new Object());
weakMap.put(x2, new Object());

然后,在清除变量和调用垃圾回收器之后,就像你已经做过的那样,我得到了输出:
Map size :3
Map size :0
Map :{}

即使调用System.gc()不能保证垃圾收集器运行,但看起来它确实在这里运行了。

当我使用你上面演示的带有new Object()的代码时,它可以正常工作,但是如果我想要像Set实现一样,当键和值具有相同引用时该怎么办? - Igal Israilevich
我不知道是否有JDK提供的类可以为Set提供类似于WeakHashMap的行为。 - rgettman
@IgalIsra 那么您可能需要使用Guava的Interner - maaartinus

1

System.gc() 实际上是运行垃圾回收器的一个建议。没有保证强制运行垃圾回收器的方法。


文档说得很清楚:“当方法调用返回时,Java虚拟机已经尽最大努力回收了所有废弃对象的空间。” - gknicker
请参考以下网址:https://dev59.com/_nVD5IYBdhLWcg3wKYP-,https://dev59.com/8HE95IYBdhLWcg3wMrAB以及其他相关资源。 - Louis Wasserman
更具体地说,请参见http://bugs.java.com/view_bug.do?bug_id=6668279,这是针对文档的错误。 - Louis Wasserman
感谢您的澄清和错误引用,我看到您是正确的。 - gknicker
“Best effort” 是服务级别协议中的术语,意为“完全没有任何保证”。 - kd8azz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接