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

(此问题不同于您为什么要实现finalize()?此问题与从Java平台弃用有关,另一个问题与在应用程序中是否应使用此机制有关。)

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

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

那么,是finalize()真的如此危险或绝对没有用,有必要将其逐出Java吗?

回答:

尽管问题是关于Object.finalize方法的问题,但主题实际上是关于 最终确定 机制的整体。该机制不仅包括表面API

Object.finalize,还包括有关对象生命周期的编程语言规范,以及对JVM中垃圾回收器实现的实际影响。

从应用程序的角度,已经写了很多关于为什么难以使用终结处理的文章。看到问题,为什么要实施finalize()?并且Java 9Cleaner是否应优先于定稿?和他们的答案。另请参阅 有效的Java,第3版, 由Joshua

Bloch,项目8。

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

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

  • 特别是当对象意外无法到达(但正确)时,它们可能会意外运行

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

  • 终结器之间没有顺序

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

  • 无法保证最终确定的及时性,甚至根本无法保证

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

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

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

系统 问题。即使使用终止的实际代码正确无误,在正确编程的系统中仍然可能出现问题。

适用于JavaSEI CERT Oracle编码标准

具有一条规则MET12-J:不要使用终结器。(请注意,这是一个有关安全编码的网站。)特别是,它说

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

Oracle的 Java

SE安全编码指南对

使用终结处理可能引起的潜在安全性问题更为明确。在这种情况下,使用终结处理的代码不是问题。取而代之的是, 攻击者

可以使用终结处理来攻击尚未适当防御的敏感代码。特别是, 准则7-3 / OBJECT-3 规定,

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

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

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

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

We’ve seen elsewhere that it’s not recommended for programmers to use

finalization. However, if something is not useful, it doesn’t necessarily

follow that it should be deprecated. The points above illustrate the fact that

even if finalization isn’t used, the mere presence of the mechanism in the

platform imposes ongoing specification, development, and maintenance costs.

Given the lack of usefulness of the mechanism and the costs it imposes, it

makes sense to deprecate it. Eventually, getting rid of finalization will

benefit everyone.

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

以上是 为什么Java 9中不推荐使用finalize()方法? 的全部内容, 来源链接: utcz.com/qa/420769.html

回到顶部