HashMap 与 WeakHashMap 一起被垃圾收集?

HashMap being garbage collected along with WeakHashMap?

根据我的理解,HashMap 不应该被垃圾回收,而 WeakHashMap 应该被垃圾回收,但是当我 运行 这段代码时,hashmap 和 weakhashmap 都被垃圾回收了。

import java.util.HashMap;
import java.util.WeakHashMap;
public class WeakHashMapDemo {
    public static void main(String[] args) {
        HashMap<String,Temp> hashMap= new HashMap<>();
        hashMap.put("a", new Temp("hashmap"));
        WeakHashMap<String,Temp> weakHashMap= new WeakHashMap<>();
        weakHashMap.put("a", new Temp("identity hashmap"));
        hashMap= null;
        weakHashMap= null;
        System.gc();
        try {
            Thread.sleep(5000);
        }catch(InterruptedException interruptedException) {
            interruptedException.printStackTrace();
        }
        System.out.println(hashMap);
        System.out.println(weakHashMap);
    }
}
class Temp {
    String name;
    Temp(String name) {
        this.name= name;
    }
    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println(name+":: Finalize Method Executed");
    }
    @Override
    public String toString() {
        return this.name;
    }
}

输出:

identity hashmap:: Finalize Method Executed
hashmap:: Finalize Method Executed
null
null

虽然仅使用 HashMap,但它不会被 GC 回收。

import java.util.HashMap;
import java.util.WeakHashMap;
public class WeakHashMapDemo {
    public static void main(String[] args) {
        HashMap<String,Temp> hashMap= new HashMap<>();
        hashMap.put("a", new Temp("hashmap"));
        System.gc();
        try {
            Thread.sleep(5000);
        }catch(InterruptedException interruptedException) {
            interruptedException.printStackTrace();
        }
        System.out.println(hashMap);
    }
}
class Temp {
    String name;
    Temp(String name) {
        this.name= name;
    }
    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println(name+":: Finalize Method Executed");
    }
    @Override
    public String toString() {
        return this.name;
    }
}

输出:

{a=hashmap}

我想你误解了 GC 的工作原理。

一句话:类 的实例在不再被引用时被垃圾回收。 与类型无关

这就是为什么注意变量范围如此重要的原因。如果您保留对不再需要的对象的引用,它将不会被收集,您将浪费资源。

此外,您正在调用 System.gc()...您不能以编程方式调用 GC。它会运行按照自己的规则。充其量,您可以 "suggest" 您希望 GC 到 运行 的 JVM。

我建议你看看:https://www.dynatrace.com/resources/ebooks/javabook/how-garbage-collection-works/

首先不要使用 finalize - 它已被弃用,有更好的方法来清理你自己并且 SO 充满了这样的帖子(ReferenceQueueSoftReferences 是其中之一)。

那就不要使用内部缓存的对象作为WeakHashMap中的键(String就是这样)。

最后一点,与WeakHashMap无关,这是Objects的基本liveliness。在您的第一个示例中,您 显式 将引用设置为 null,因此它们会被 GC 清除,而在您的第二个示例中则不会,并通过System.out.println(hashMap);;因此它不会被收集。

在您的第一个示例中,您将 hashMap 变量设置为 null。然后不再有对 HashMap 对象的引用,它可以像任何其他类型的对象一样被垃圾收集。 HashMapWeakHashMap 在这方面没有什么不同。

区别在于 WeakHashMap 中的 keys 在没有外部引用时可能会被垃圾回收。在正常的 HashMap 中,这不会发生,因为映射本身包含对键的引用。

收集到密钥后,WeakHashMap 可能会清除整个相应的条目。 详细介绍。

在第 hashMap= null; 行,您解除了对 HashMap 对象的引用。在任何情况下设置 null 后,在垃圾收集的下一个循环中它将由垃圾收集器收集。

在第二种情况下,您没有将 hashMap 设置为 null。

两者的区别:

WeakHashMap 是 Map 接口的一个实现。 WeakHashMap 几乎与 HashMap 相同,除了 WeakHashMap 的情况,如果对象被指定为键不包含任何引用 - 即使它与 WeakHashMap 相关联,它也有资格进行垃圾收集。即垃圾收集器在 WeakHashMap 上占主导地位。