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 充满了这样的帖子(ReferenceQueue
和 SoftReferences
是其中之一)。
那就不要使用内部缓存的对象作为WeakHashMap
中的键(String
就是这样)。
最后一点,与WeakHashMap
无关,这是Objects的基本liveliness。在您的第一个示例中,您 显式 将引用设置为 null
,因此它们会被 GC 清除,而在您的第二个示例中则不会,并通过System.out.println(hashMap);
;因此它不会被收集。
在您的第一个示例中,您将 hashMap
变量设置为 null
。然后不再有对 HashMap 对象的引用,它可以像任何其他类型的对象一样被垃圾收集。 HashMap
和 WeakHashMap
在这方面没有什么不同。
区别在于 WeakHashMap
中的 keys 在没有外部引用时可能会被垃圾回收。在正常的 HashMap
中,这不会发生,因为映射本身包含对键的引用。
收集到密钥后,WeakHashMap
可能会清除整个相应的条目。 详细介绍。
在第 hashMap= null;
行,您解除了对 HashMap 对象的引用。在任何情况下设置 null 后,在垃圾收集的下一个循环中它将由垃圾收集器收集。
在第二种情况下,您没有将 hashMap 设置为 null。
两者的区别:
WeakHashMap 是 Map 接口的一个实现。 WeakHashMap 几乎与 HashMap 相同,除了 WeakHashMap 的情况,如果对象被指定为键不包含任何引用 - 即使它与 WeakHashMap 相关联,它也有资格进行垃圾收集。即垃圾收集器在 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 充满了这样的帖子(ReferenceQueue
和 SoftReferences
是其中之一)。
那就不要使用内部缓存的对象作为WeakHashMap
中的键(String
就是这样)。
最后一点,与WeakHashMap
无关,这是Objects的基本liveliness。在您的第一个示例中,您 显式 将引用设置为 null
,因此它们会被 GC 清除,而在您的第二个示例中则不会,并通过System.out.println(hashMap);
;因此它不会被收集。
在您的第一个示例中,您将 hashMap
变量设置为 null
。然后不再有对 HashMap 对象的引用,它可以像任何其他类型的对象一样被垃圾收集。 HashMap
和 WeakHashMap
在这方面没有什么不同。
区别在于 WeakHashMap
中的 keys 在没有外部引用时可能会被垃圾回收。在正常的 HashMap
中,这不会发生,因为映射本身包含对键的引用。
收集到密钥后,WeakHashMap
可能会清除整个相应的条目。
在第 hashMap= null;
行,您解除了对 HashMap 对象的引用。在任何情况下设置 null 后,在垃圾收集的下一个循环中它将由垃圾收集器收集。
在第二种情况下,您没有将 hashMap 设置为 null。
两者的区别:
WeakHashMap 是 Map 接口的一个实现。 WeakHashMap 几乎与 HashMap 相同,除了 WeakHashMap 的情况,如果对象被指定为键不包含任何引用 - 即使它与 WeakHashMap 相关联,它也有资格进行垃圾收集。即垃圾收集器在 WeakHashMap 上占主导地位。