问题 JVM / GC是否在程序/线程退出时调用`finalize()`?


PS:我确实知道如何正确清理,而不依赖于 finalize()

Java不能保证在程序退出时,会进行适当的垃圾收集吗?

例如。假设我已经在缓存中保留了一些数据而不是频繁地序列化,我也实现了 finalize() 希望如果由于任何原因(崩溃除外)我的程序正常退出,那么缓存将通过我的代码在finalize()方法中写入DB / file / some-storage。但根据以下小实验,似乎JVM不会“优雅地”清理内存,它只是退出。

Java规范 (参见程序退出)说明没有在退出时如何处理内存/ gc。或者我应该查看规范的不同部分?

在Windows 7上使用1.6.0.27 64位进行以下示例(最后输出)

public class Main {

        // just so GC might feel there is something to free..
    private int[] intarr = new int[10000];

    public static void main(String[] args) {
        System.out.println("entry");
        Main m = new Main();
        m.foo();
        m = new Main();
        // System.gc();
        m.foo();
        m = null;
        // System.gc();
        System.out.println("before System.exit(0);");
        System.exit(0);
    }

    @Override
    protected void finalize() throws Throwable {
        System.out.println("finalize()");
        super.finalize();
    }

    public void foo() { System.out.println("foo()"); }
}

/*
 * Prints:
 * entry 
 * foo() 
 * foo() 
 * before System.exit(0);
 */

变化:

  • 如果我取消注释任何一个 System.gc() 那就不要 finalize() 叫做。
  • 如果我取消两个 System.gc() 然后 finalize() 被叫两次。
  • 是否 System.exit() 被叫或不对是否有影响 finalize() 是否被召唤。

6245
2017-10-24 19:06


起源

你遇到的问题是一个程序可能随时都会失败。您可能还需要能够在重新启动时进行清理。 - Peter Lawrey


答案:


不,Java不保证在程序退出时GC会触发。如果您希望在退出时使用操作 Runtime.addShutdownHook 方法。读 这个 有关SPEC所说内容的Sun文章。

Java平台的规范很少有人承诺   垃圾收集实际上如何工作。这是Java Virtual的内容   机器规范(JVMS)必须说明内存管理。

堆是在虚拟机启动时创建的。堆存储   对象由自动存储管理系统回收(已知   作为垃圾收集者);对象永远不会被显式释放。该   Java虚拟机假定没有特定类型的自动存储   管理系统和存储管理技术可以选择   根据执行者的系统要求.1虽然看起来如此   令人困惑的是,垃圾收集模型并不严格   定义实际上是重要且有用的 - 严格定义的垃圾   集合模型可能无法在所有平台上实现。   同样,它可能排除有用的优化并伤害到   从长远来看平台的性能。

虽然没有一个地方包含完整的定义   所需的垃圾收集器行为,很多GC模型都是   通过Java语言中的许多部分隐式指定   规范和JVMS。虽然没有确切的保证   随后进程,所有兼容的虚拟机共享基本   本章描述的对象生命周期。


10
2017-10-24 19:08



它(例如规格)是否在任何地方都这样说? - Kashyap
虽然你提供的描述仍然没有真正说明GC在退出时没有完成,但我认为它已经足够明确它留给了JVMs impls ..感谢您的信息abt addShutdownHooks(),不知道.. - Kashyap
规范中没有否定的陈述,即“GC不一定在退出时运行”。我所引用的规范中的故意模糊和广泛的陈述都是陈述的。 - Amir Afghani
确实..我当然不是要看到确切的陈述,但我至少希望在规范中看到一些描述退出时JVM责任的内容。无论如何..这更需要学习而不是需要,所以你的答案是可以接受的。 - Kashyap
我只是想进一步澄清这一点......不能保证GC会提交......即使它确实存在;无法保证GC将删除对象并调用finalize()。即使你打电话 System.gc() 在退出之前,对象可能仍然没有触发finalize()。 - Philip Couling


看到 Runtime.runFinalizersOnExit()。请注意,它已弃用,请注意其余评论。我认为你可以合法地推断它默认是关闭的,但是你也应该注意它可以打开。


3
2017-10-25 01:29