java - 为什么在Java 9中不推荐使用finalize()方法?

标签 java java-9 finalize

(此问题与Why would you ever implement finalize()?不同。此问题是关于从Java平台弃用的,而另一个问题是,是否应在应用程序中使用此机制。)

为什么在Java 9中不推荐使用finalize()方法?

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

那么finalize()真的那么危险或绝对无用,有必要将其赶出Java吗?

最佳答案

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

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

简要地说,有关使用终结器的问题的几点是:

众所周知,它们很难正确编程 特别是

  • ,当对象出现时它们可能会意外运行
    意外地变得无法访问(但正确);例如,
    参见my answer to this question
  • 终结可以轻松打破子类/父类(super class)关系
  • 终结器之间不排序
  • 给定对象的finalize方法最多由JVM调用一次,即使该对象已“复活”
  • 无法保证最终定稿或
    即使它会全部运行
  • 没有明确的注册或注销机制

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

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

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

    最终定稿有助于安全性问题

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

    Improper use of finalizers can result in resurrection of garbage-collection-ready objects and result in denial-of-service vulnerabilities.



    Oracle的Secure Coding Guidelines for Java SE更明确地说明了使用终结处理可能引起的潜在安全问题。在这种情况下,使用终结处理的代码不是问题。取而代之的是,攻击者可以使用终结处理来攻击尚未适当防御的敏感代码。特别是,准则7-3/OBJECT-3指出,

    Partially initialized instances of a non-final class can be accessed via a finalizer attack. The attacker overrides the protected finalize method in a subclass and attempts to create a new instance of that subclass. This attempt fails ... but the attacker simply ignores any exception and waits for the virtual machine to perform finalization on the partially initialized object. When that occurs the malicious finalize method implementation is invoked, giving the attacker access to this, a reference to the object being finalized. Although the object is only partially initialized, the attacker can still invoke methods on it....



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

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

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

    终结处理为实现增加了复杂性

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

    摘要

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

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

    关于java - 为什么在Java 9中不推荐使用finalize()方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56139760/

    相关文章:

    java - 警告 : [path] the output directory is within an exploded module java 9

    c# - 析构函数和终结器方法的区别

    java - finalizable 对象如何至少需要 2 个垃圾收集周期才能被回收?

    java - 在Java中合并两个数组以保持顺序并使用第一个数组的唯一空白值

    java - 对于任何程序,我必须在 Java 中使用哪些常见导入?

    java - 抛出异常后,jshell 继续执行我的脚本。如何让它停止?

    java - 从 java8 迁移到 java9 时,对方法的引用不明确

    java - finalize() 在 Java 中如何工作?

    java - 在 MySQL 数据库中存储微秒

    java - Log4j 每个实例写入一个文件