我只是不明白为什么必须使用Runtime.addShutdownHook。如果你想在jvm退出时做一些清理,为什么不重载daemon类的finalize方法。使用shutdown hook而不是finalize方法有什么好处。
还有一个不推荐使用的函数runFinalizersOnExit。如果我将其设置为false,我相信终结器将无法运行。这与java保证终结器总是在垃圾收集之前运行相矛盾。
答案 0 :(得分:21)
无法保证终结器永远运行。当对象被垃圾收集时调用finalize()
。但是当程序运行时,垃圾收集器可能不会收集任何东西。
当jvm正常退出时,运行对比关闭挂钩。所以,即使这不是100%保证,但它非常接近。只有少数边缘情况不会运行关闭挂钩。
修改强> 我查找了未执行关闭挂钩的边缘情况
执行关闭挂钩 IS :
关闭挂钩未执行:
答案 1 :(得分:4)
关于您的查询
如果你想在jvm退出时做一些清理,为什么不重载守护进程类的finalize方法
我从article
中找到了很好的信息 finalize()
。调用此方法时,JVM不保证。
finalize()
只能通过GC线程调用一次,如果object从finalize方法中恢复,则不会再次调用finalize。
在您的应用程序中,您可能有一些活动对象,永远不会在其上调用垃圾收集。
GC线程忽略了finalize方法引发的任何异常
System.runFinalization(true)
和Runtime.getRuntime().runFinalization(true)
方法增加了调用finalize()
方法的可能性,但现在这两种方法已被弃用。由于缺乏线程安全性和可能的死锁创建,这些方法非常危险。
按照oracle documentation
返回shutdownHookspublic void addShutdownHook(Thread hook) 注册一个新的虚拟机关闭钩子。
Java虚拟机关闭以响应两种事件:
但即便是oracle文档引用了
关机挂钩也应该快速完成工作。当程序调用exit时,期望虚拟机将立即关闭并退出。
在极少数情况下,虚拟机可能会中止,即停止运行而不会干净地关闭
考虑到这两种方法的缺点,您应该遵循以下方法
不要依赖finalize()
或shutdown hooks
来释放您应用中的关键资源。
适当地使用try{} catch{} finally{}
块并在finally(}
块中释放关键资源。在finally{}
块中释放资源期间,请抓住Exception
和Throwable
。