我有以下代码:
public class MyOjbect {
public Integer z = 111;
@Override
protected void finalize() throws Throwable {
System.out.println("invoking GC in MyOjbect");
super.finalize();
}
}
public class GC {
private MyOjbect o;
private void doSomethingElse(MyOjbect obj) {
o = obj;
}
@SuppressWarnings("unused")
public void doSomething() throws InterruptedException {
System.out.println("Start");
MyOjbect o = new MyOjbect();
doSomethingElse(o);
o = new MyOjbect();
doSomethingElse(null);
System.gc();
// System.out.println("checking "+o.z);
}
public static void main(String[] args) throws InterruptedException {
GC gc = new GC();
gc.doSomething();
}
}
我想知道为什么执行GC
方法后o
垃圾doSomethingElse
变量。即使o
变量尚未归零。实际上,当我在o
之后调试代码doSomethingElse
时,它不是空的,而是GC
垃圾。此外,如果我取消注释最后一行,GC打印o.z
变量,之后调用GC。
更新:对于询问为什么局部变量与字段相同的人。我刚刚从SCJP测试考试中复制了一个问题,因为它是
答案 0 :(得分:1)
在这里讨论很多科目!
首先,正如Gyro所说,GC不收集变量。它收集死对象的实例。死对象是一个没有强引用(变量)的对象。请注意,有更微妙的情况(弱引用,软引用,幻影引用,......),但让我们关注最常见的情况:-)您可以在此处找到有关此内容的更多信息:https://weblogs.java.net/blog/2006/05/04/understanding-weak-references
如果取消注释最后一行,则会打印“111”,因为o是引用您使用o = new MyOjbect();
创建的MyObject实例的局部变量。
现在,最棘手的事情是:你有两个不同的MyObject实例。但是,您的程序只打印一次“在MyObject中调用GC”。如果您像这样转换“MyObject”类,那就很明显了:
public class MyOjbect {
public Integer z = 111;
public MyOjbect() {
System.out.println("Creating MyObject " + hashCode());
}
@Override
protected void finalize() throws Throwable {
System.out.println("invoking GC in MyOjbect " + hashCode());
super.finalize();
}
}
您的程序现在打印两个MyObjects创建,但只有一个由GC恢复。这是因为绝对不能保证调用finalize()方法。根据JLS和finalize()的javadoc:
Java编程语言不保证哪个线程会 为任何给定对象调用finalize方法
在您的情况下,应用程序的结尾使每个对象都死了。无需运行GC,因为一旦JVM退出,堆将完全恢复。