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

时间:2011-10-24 19:06:50

标签: java

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

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

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

Java spec(参见程序退出)说明了在退出时如何处理内存/ 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()没有影响。

2 个答案:

答案 0 :(得分:10)

不,Java不保证在程序退出时GC会触发。如果要在退出时使用Runtime.addShutdownHook方法执行操作。阅读this Sun有关SPEC所说内容的文章。

  

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

     

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

     

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

答案 1 :(得分:3)

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