为什么Java 10中不建议使用finalize()方法?

时间:2019-05-14 23:08:58

标签: java finalize

我的问题不同于^^^^^^,请参阅底部的说明

为什么在Java 10中不建议使用finalize()方法?

是的,它可能以错误的方式使用(例如,从垃圾收集中保存对象[仅一次]或尝试关闭其中的某些本机资源[总比不完全关闭要好])以及许多其他方法可能会错误使用。.

那么finalize()方法真的那么危险或绝对没有必要将其从Java中踢出来吗?

我的问题与为什么要实施finalize()仅仅是因为我问的是弃用,而不是用例

2 个答案:

答案 0 :(得分:5)

尽管问题是关于Object.finalize方法的问题,但主题实际上是关于整个 finalization 机制的问题。该机制不仅包括表面API Object.finalize,还包括有关对象生命周期的编程语言规范,以及对JVM中垃圾回收器实现的实际影响。

从应用程序的角度出发,已经写了很多关于为什么难以使用finalization的文章。请参阅问题Why would you ever implement finalize()?Should Java 9 Cleaner be preferred to finalization?及其答案。另请参见Joshua Bloch撰写的 Effective Java,第3版,第8项。

简而言之,有关使用终结器的问题的几点是:

  • 众所周知,他们很难正确编程

  • 尤其是当一个对象出现时,它们可能会意外运行 因为意外(但正确)无法到达;例如, 参见my answer to this question

  • 最终确定可以轻松打破子类/超类关系

  • 终结器之间没有排序

  • 给定对象的finalize方法最多由JVM调用一次,即使该对象“已复活”

  • 不能保证最终定稿的及时性或 甚至完全可以运行

  • 没有明确的注册或注销机制

以上是使用finalization的困难。考虑到上述问题,正在考虑使用终结处理的任何人都应重新考虑。但是这些问题足以否决Java平台中的终结处理吗?以下各节还解释了一些其他原因。

最终确定可能会使系统易碎

即使编写的对象正确使用了终结处理,当将对象集成到较大的系统中时,也会引起问题。即使您根本不使用终结处理,将其集成到较大的系统中(其中某些部分使用终结处理)也可能导致问题。通常的问题是,创建垃圾的工作线程需要与垃圾收集器保持平衡。如果垃圾收集器落后了,那么至少某些收集器可以“阻止世界”并进行完整的收集以赶上。终结使这种交互复杂化。即使垃圾收集器跟上了应用程序线程的速度,终结处理也可能会导致瓶颈并降低系统速度,或者可能导致释放资源时出现延迟,从而导致这些资源的耗尽。这是一个系统问题。即使使用终结符的实际代码正确无误,在正确编程的系统中仍然可能出现问题。

最终确定会导致安全问题

SEI CERT Java Java编码标准具有规则MET12-J: Do not use finalizers。 (请注意,这是一个有关安全编码的网站。)特别是,它说

  

终结符使用不当会导致垃圾回收就绪对象的复活,并导致拒绝服务漏洞。

Oracle的Secure Coding Guidelines for Java SE对于使用终结处理可能引起的潜在安全问题更为明确。在这种情况下,使用终结处理的代码不是问题。取而代之的是,攻击者 可以使用终结处理来攻击没有适当防御的敏感代码。特别是,指南7-3 / OBJECT-3 部分声明

  

可以通过终结器攻击来访问非最终类的部分初始化实例。攻击者将覆盖子类中受保护的finalize方法,并尝试创建该子类的新实例。这种尝试失败了……但是攻击者只是忽略了任何异常,而是等待虚拟机对部分初始化的对象执行最终化。发生这种情况时,将调用恶意的finalize方法实现,从而使攻击者可以访问this,这是对最终确定对象的引用。尽管对象只是部分初始化,但攻击者仍可以在其上调用方法。...

因此,平台中终结机制的存在给试图编写高保证代码的程序员带来了负担。

最终确定会增加规格的复杂性

Java平台由多种规范定义,包括语言,虚拟机和类库API的规范。最终化的影响在所有这些方面都散布得很细,但它反复使人感觉到它的存在。例如,完成与对象创建之间的交互非常微妙(这已经足够复杂了)。 Finalization也已经出现了Java的公共API,这意味着(到目前为止)需要对这些API进行改进,以保持与先前指定行为的兼容性。不断完善这些规范会使最终确定的成本更高。

最终确定会给实现带来复杂性

这主要是关于垃圾收集器的。有几种垃圾回收实现,所有这些都需要支付实现终结点的成本。如果不使用终结处理,则这些实现非常擅长于将运行时开销最小化。但是,实现仍然需要存在,并且需要正确且经过良好测试。这是持续的开发和维护负担。

摘要

我们在其他地方已经看到,不建议程序员使用终结处理。但是,如果某些内容没有用处,则不一定要弃用它。以上几点说明了一个事实,即即使不使用终结处理,平台中机制的存在也会带来不断增加的规范,开发和维护成本。鉴于该机制缺乏实用性和所施加的成本,因此不建议使用该机制。最终,摆脱终结定论将使所有人受益。

截至撰写本文(2019-06-04)时,尚无具体计划从Java中删除终结处理。但是,这样做当然是有意图的。我们已弃用Object.finalize方法,但尚未将其标记为删除。这是程序员停止使用此机制的正式建议。非正式地知道不应该使用终结处理,但是当然有必要采取正式的步骤。另外,不推荐使用库类中的某些finalize方法(例如ZipFile.finalize)“删除”,这意味着这些类的最终确定行为可能会从将来的版本中删除。最终,我们希望在JVM中禁用终结处理(也许是可选的,然后默认是禁用,然后在以后默认),并在将来的某个时候从垃圾收集器中真正删除终结处理实现。

答案 1 :(得分:-3)

最终确定机制本质上是有问题的。终结处理可能会导致性能问题,死锁和挂起。终结器中的错误可能导致资源泄漏;