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

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

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

例如,假设我已经在缓存中保留了一些数据而不是频繁地序列化,我还实现了finalize() ,希望如果由于任何原因(崩溃除外)我的程序正常退出,那么缓存将被写入DB /我的代码在finalize()方法中的文件/一些存储。 但根据以下小实验,似乎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()没有影响。

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

Java平台的规范很少有关于垃圾收集实际工作方式的承诺。 以下是Java虚拟机规范(JVMS)对内存管理的看法。

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

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

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