我们可以关闭终结器吗



由于几乎不能保证终结器何时运行,即使终结器现在几乎被认为是一种气味,有什么方法可以说服JVM完全跳过所有的终结过程吗?

我之所以这么问,是因为我们有一个庞大的应用程序,当它被移动到一个新的JVM(现阶段不确定是哪个)时,它会因为与finalizer的已知问题(抛出异常,因此GC非常慢)而屈服。

添加

有一些关于java内存泄漏故障排除的讨论:终结?有人建议,当在终结器中抛出异常时,主要问题会出现,因为这会大大减慢终结过程。

当内存变低,堆转储分析显示大量Finalizer对象(超过10000000个)时,我的问题显示为速度急剧下降,这表明速度下降可能是他们的错,因为他们正在延迟GC。显然我可能错了。

我没有能力要求进行重构。

有什么方法可以说服JVM完全跳过所有的完成过程吗?

在一个单词编号中

但是,除非您的对象中有很大一部分具有finalize方法和/或finalize方法特别昂贵,否则我认为它们不太可能使GC"非常慢"。我想问题出在其他方面。

我建议您打开GC日志记录,以便更好地了解实际发生的情况。

但我也同意,从长远来看,重构代码以摆脱finalize()方法可能是一件好事。(在极少数情况下,使用finalize确实是最佳解决方案。)


更新-你的新证据很有说服力,尽管不是证据!。

我没有能力要求重构。

那么,我建议你把证据放在那些这样做的人的脚下:-)。

或者,您可以向可疑的finalize方法添加一个异常处理程序,以查看它们是否正在抛出异常。(如果是,则更改它们以避免抛出异常…)

但最重要的是,如果最终确定是导致性能问题的真正原因,那么解决这些问题的最佳(可能也是唯一)方法就是更改代码。

可以抑制某些对象的终结。正如一位评论者所指出的,它不需要字节码操作。

这里描述了该过程,并提供了源代码。类java.lang.ref.Finalizer负责维护尚未最终确定的对象的列表。要抑制感兴趣对象的终结,只需使用反射API获取字段lock上的锁,迭代Finalizer类维护的链表unfinalized,并从该列表中删除对象即可。

我已经尝试过这种方法来安全地实例化自定义序列化对象,同时绕过构造函数调用,避免使用普通GC调用终结器时出现问题。在应用这个方法之前,我的JVM会在终结器线程中出现硬故障;由于采用了这种方法,故障就不会发生。

Java 18(2022年发布)不赞成使用JEP 421删除最终版本,并添加了禁用选项。

现在,您可以使用--finalization=disabled启动应用程序,它不会运行终结器。

java --finalization=disabled -jar your-app.jar

JEP还提到了一个名为jdk.FinalizerStatistics的JFR事件,它为您提供了更多关于定稿的信息:

# start Java with the JFR event jdk.FinalizerStatistics enabled
java -XX:StartFlightRecording:filename=recording.jfr -jar your-app.jar
# print events
jfr print --events FinalizerStatistics recording.jfr

您不能在java中关闭finalizer,但您所能做的就是编写有助于GC的代码:-)。

相关内容

最新更新