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

2022-09-04 20:58:15

PS:我确实知道如何正确清理,而无需依赖.finalize()

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

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

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()

答案 1

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

Java平台的规范对垃圾回收的实际工作原理几乎没有做出任何承诺。以下是 Java 虚拟机规范 (JVMS) 对内存管理的看法。

堆是在虚拟机启动时创建的。对象的堆存储由自动存储管理系统(称为垃圾回收器)回收;对象从不显式解除分配。Java 虚拟机假定没有特定类型的自动存储管理系统,可以根据实现者的系统要求选择存储管理技术。1 虽然看起来令人困惑,但垃圾回收模型没有严格定义这一事实实际上很重要且有用 - 刚定义垃圾回收模型可能无法在所有平台上实现。同样,从长远来看,它可能会排除有用的优化并损害平台的性能。

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


答案 2

请参阅 Runtime.runFinalizersOnExit()。。请注意,它已被弃用,并注意评论的其余部分。我认为您可以从所有内容中合法地推断出默认情况下它是关闭的,但是您还应该注意它可以打开。


推荐