Java 中的 WeakReference 和 StrongReference 的 GC
GC for a WeakReference and StrongReference in Java
我在 java api 文档中阅读了一些关于 Java 7 的弱引用的文献,并尝试使用以下内容进行测试
package com.finalize;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
public class WeakRefernceTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
String x = new String("x1");
String y = new String("x2");
Map<String, Object> mw = new WeakHashMap<>();
mw.put(x, new Object());
Map<String, Object> m = new HashMap<>();
m.put(y, new Object());
x = null;
y = null;
for(int i = 0; i < 5;++i)
System.gc();
System.out.println(mw.size());
System.out.println(m.size());
}
}
当我多次 运行 时,我可以看到 mw.size() 打印为 0。但我有点困惑,因为 m.size() 从未打印为0. 所以基本上,我试图了解这个热点 jvm 中 运行 的默认 GC。那么当GC开始标记可达对象时,x和y设置为null后运行,为什么因为y已经设置为null而将y所指的对象标记为可达对象呢?即使根变量设置为 m,为什么 GC 会到达 y 之前指向的对象并声明它是可达的?
相比之下,x 上生命周期变化的详细顺序是什么?
单步执行您的代码
- 您复制字符串
"x2"
并将其分配给 y
- 您将字符串
"x2"
添加为 m
中的键
- 当您进行 GC 时,
m
是可访问的,它的所有键都是可访问的。
- 在 GC 之后,
m
及其所有键都被保留。
您正在主线程上执行 main 方法。主线程的堆栈上有变量 m
。此变量 m
是对 HashMap 实例的引用。此 HashMap 实例具有对映射条目数组的引用。此数组中包含的唯一映射条目具有对 "x2" 键和相应对象的引用。
因此存在从根(主线程堆栈)到映射中存储的对象的强大引用链。这会阻止 GC 收集映射中的对象。
thread stack -> m -> HashMap -> entries -> entry -> "x2"
-> Object
另一个映射和另一个对象也是如此,除了它是一个 WeakHashMap,所以因为映射键是一个弱引用并且是唯一指向的引用"x1",允许 GC 收集对 "x1" 的引用。一旦 GC 收集了它,地图就会从其数组中删除相应的条目。
我在 java api 文档中阅读了一些关于 Java 7 的弱引用的文献,并尝试使用以下内容进行测试
package com.finalize;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
public class WeakRefernceTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
String x = new String("x1");
String y = new String("x2");
Map<String, Object> mw = new WeakHashMap<>();
mw.put(x, new Object());
Map<String, Object> m = new HashMap<>();
m.put(y, new Object());
x = null;
y = null;
for(int i = 0; i < 5;++i)
System.gc();
System.out.println(mw.size());
System.out.println(m.size());
}
}
当我多次 运行 时,我可以看到 mw.size() 打印为 0。但我有点困惑,因为 m.size() 从未打印为0. 所以基本上,我试图了解这个热点 jvm 中 运行 的默认 GC。那么当GC开始标记可达对象时,x和y设置为null后运行,为什么因为y已经设置为null而将y所指的对象标记为可达对象呢?即使根变量设置为 m,为什么 GC 会到达 y 之前指向的对象并声明它是可达的?
相比之下,x 上生命周期变化的详细顺序是什么?
单步执行您的代码
- 您复制字符串
"x2"
并将其分配给y
- 您将字符串
"x2"
添加为m
中的键
- 当您进行 GC 时,
m
是可访问的,它的所有键都是可访问的。 - 在 GC 之后,
m
及其所有键都被保留。
您正在主线程上执行 main 方法。主线程的堆栈上有变量 m
。此变量 m
是对 HashMap 实例的引用。此 HashMap 实例具有对映射条目数组的引用。此数组中包含的唯一映射条目具有对 "x2" 键和相应对象的引用。
因此存在从根(主线程堆栈)到映射中存储的对象的强大引用链。这会阻止 GC 收集映射中的对象。
thread stack -> m -> HashMap -> entries -> entry -> "x2"
-> Object
另一个映射和另一个对象也是如此,除了它是一个 WeakHashMap,所以因为映射键是一个弱引用并且是唯一指向的引用"x1",允许 GC 收集对 "x1" 的引用。一旦 GC 收集了它,地图就会从其数组中删除相应的条目。