尽管主线程正在使用对象的最终确定

时间:2017-04-27 06:06:57

标签: java garbage-collection

在JDK 8上,我运行了以下代码,发现它每次都会完成A。如果我在最后取消对println的评论,A永远不会被最终确定。

public class A {
    @Override protected void finalize() {
        System.out.println(this + "object is eligible for garbage collection");
    }

    public static void main(String[] args) {
        A a = new A();
        System.out.println("Main thread created object " + a);
        for (int i = 0; i < 1000000000; i++) {
            if (i % 100000000 == 0)
                // Force GC
                System.gc();
        }
        //If i un-comment below it won't do garbage collection ever
       //  System.out.println(a + "is residing on heap and is alive");
    }
}

有人可以解释一下这种行为,在syso()之后会发生什么,为什么它还没有最终确定。

2 个答案:

答案 0 :(得分:0)

JVM的最新版本中的垃圾收集遵循优化原则来确定对象是否超出了已执行程序的范围。
它很少局限于该方法的范围。

来自Oracle documentation

什么是自动垃圾收集?

  

自动垃圾收集是查看堆内存的过程,   识别正在使用哪些对象以及哪些对象未被删除   未使用的对象。使用中的对象或引用的对象是指   程序的某些部分仍然保持指向它的指针   宾语。不再使用未使用的对象或未引用的对象   由程序的任何部分引用。所以内存使用的是   可以回收未引用的对象。

最后两句话很重要:

程序的任何部分都不再引用未使用的对象或未引用的对象。因此,可以回收未引用对象使用的内存。

在您的示例代码中:

public static void main(String[] args) {
    A a = new A();
    System.out.println("Main thread created object " + a);
    for (int i = 0; i < 1000000000; i++) {
        if (i % 100000000 == 0)
            System.gc();
    }
}

当调用System.gc();时,程序的任何部分都不再引用a,因此垃圾收集请求可能会将其标记为已释放。

现在添加System.out.println(a + "is residing on heap and is alive");     },从来没有调用终结器可能是有意义的。 调用gc()时不会调用它,因为它仍被引用,但sysout也是程序的最后一行。

a实例是主线程类(A)的实例 如果主线程已完成,则当前JVM进程已关闭 在这些条件下,它的finalize()方法可能无法执行。

Ps:对不起多次修改。我在打电话......

答案 1 :(得分:0)

如果没有额外的System.out.println(a + "is residing on heap and is alive");行,a循环前for 符合条件适用于GC。它不再被主线程使用,与你的问题所说的相反。是否GC'd(和终结器运行)不是应该关心的事情。您不能/不应该编写对GC行为做出假设的代码。

使用注释掉的行,a直到之后才有资格获得GC,此时JVM退出已经太晚了,至少在你的情况下终结器没有运行。

这是正常行为,但正如我们所知,you can't trust that the finalizers will or will not be run。您可能会在不同的环境中遇到不同的结果。