我是Java的新学习者。我现在正在学习WeakReference的概念。我遇到了一个可能看起来很愚蠢的问题,但我只是想弄清楚原因。问题是:根据Java doc,"弱引用对象,它们不会阻止它们的引用被最终化,最终化,然后回收。"
所以我做了这个小测试:
import java.lang.ref.WeakReference;
public class A {
public static void main(String[] args) {
A a = new A();
WeakReference<A> wr = new WeakReference<>(a);
a = null;
A a1 = wr.get();
System.out.println(a);
System.out.println(a1);
try {
System.gc();
Thread.sleep(10000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(a1);
}
@Override
protected void finalize( ) {
System.out.println(Thread.currentThread().getName() + ": See ya, nerds!");
}
}
但是,我注意到在GC运行后,wr.get()
仍然可以返回我期望为null的对象,并且未调用方法finalize()
。出了什么问题?感谢您的帮助! :)
答案 0 :(得分:3)
您的测试前提是有缺陷的。 System.gc()
只是提示来运行垃圾收集器。它经常被忽略。
调用gc方法建议表示Java虚拟机 努力回收未使用的物体,以便制造 他们目前占用的内存可用于快速重用。控制时 从方法调用返回,Java虚拟机做得最好 努力从所有废弃物体中回收空间。
(强调我的)
将来,您可以使用VM选项-verbose:gc
和-XX:+PrintGCDetails
来查看垃圾收集器正在执行的操作。
更重要的是,您也非常快从弱引用中获取引用并将其重新引入强引用:
A a = new A();
WeakReference<A> wr = new WeakReference<>(a);
a = null; // no strong references remain
A a1 = wr.get(); // the instance now has a strong reference again
除非在这两个指令之间发生垃圾收集,否则该对象不会被垃圾收集。
如果你删除a1
,你的代码就像我在运行它时所期望的那样(但是,由于我的答案的第一部分,你的里程可能会有所不同):
class A
{
public static void main(String[] args)
{
A a = new A();
WeakReference<A> wr = new WeakReference<>(a);
a = null;
System.out.println(a);
try {
System.gc(); // instance of A is garbage collected
Thread.sleep(10000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(wr.get());
}
@Override
protected void finalize( )
{
System.out.println(Thread.currentThread().getName() + ": See ya, nerds!");
}
}
答案 1 :(得分:0)
首先,System.gc()
无法确保垃圾回收。相反,它只是暗示“这是运行垃圾收集的好时机”。
其次,在调用A a1 = wr.get();
之前放置System.gc()
的代码中,它会创建对a
引用的同一对象的新强引用,因此即使垃圾收集运行,对象不会被垃圾收集。
因为我们手头有两项任务
让我们对您的代码进行一些修改
public class A {
public static void main(String[] args) {
A a = new A();
WeakReference<A> wr = new WeakReference<>(a);
a = null;
// A a1 = wr.get(); Removing this, this does our 2nd task
System.out.println(a);
// System.out.println(a1); Removing this as a1 does not exists anymore
try {
while (null != wr.get()) { // 1st task done, the loop ensures sending the hint until your object collected
System.gc();
// Thread.sleep(10000); it does not have impact
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(wr.get()); // Obviously prints null
}
@Override
protected void finalize() {
System.out.println(Thread.currentThread().getName() + ": See ya, nerds!");
}
}