JAVAGC的奇怪行为

时间:2013-04-30 04:31:46

标签: java garbage-collection

我有以下代码:

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测试考试中复制了一个问题,因为它是

1 个答案:

答案 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退出,堆将完全恢复。