首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java如何调用finalize()方法?

Java如何调用finalize()方法?
EN

Stack Overflow用户
提问于 2016-12-22 18:33:45
回答 4查看 1.5K关注 0票数 6

据我所知,GC从一些初始对象(堆栈、静态对象)开始,然后递归遍历它,构建一个可访问对象的图表。然后,它将这些对象占用的内存标记为已占用的内存,并假定其余的内存都是空闲的。

但是,如果这个“空闲”内存包含一个带有finalize方法的对象,该怎么办?GC不得不调用它,但我看不出它是如何知道已经无法访问的对象的。

我认为GC可以在所有的“可终结”对象活着的时候跟踪它们。如果是这样的话,拥有可完成的对象是否会使垃圾收集变得更昂贵,即使它们还活着?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2016-12-22 19:05:14

考虑一下参考API

它为GC提供了一些具有特殊语义的引用,即弱引用、软引用和幻影引用。对于需要最后确定的对象,还有另一种非public类型的特殊引用。

现在,当垃圾收集器遍历对象图并遇到这样一个特殊的引用对象时,它将不会将通过此引用可访问的对象标记为强可达,而是使用特殊的语义可到达。因此,如果一个对象仅是可到达的终结器,则引用将排队,以便一个(或其中一个)终结器线程能够轮询队列并执行finalize()方法(不是垃圾收集器本身调用此方法)。

换句话说,垃圾收集器永远不会在这里处理完全无法到达的对象。要将特定的语义应用于可达性,引用对象必须是可访问的,因此可以通过该引用到达引用。在终结器可达性的情况下,在创建对象并依次创建Finalizer的实例、FinalReference的子类和就在它的构造函数中时,将调用add()方法,该方法将将引用插入到全局链接列表中。因此,所有这些FinalReference实例都可以通过该列表访问,直到实际完成为止。

由于这个FinalReference将在对象实例化时创建,如果它的类声明了一个非平凡的finalize()方法,则由于有一个终结需求,已经存在一些开销,即使该对象尚未收集。

另一个问题是,由终结器线程处理的对象可以被该线程访问,甚至可能转义,这取决于finalize()方法所做的事情。但是下一次,当这个对象变得不可访问时,这个特殊的引用对象就不存在了,所以它可以像任何其他不可访问的对象一样被处理。

这只是一个性能问题,如果内存非常低,并且下一个垃圾回收必须更早地执行,才能最终回收该对象。但在参考实现(也称为“HotSpot”或“OpenJDK”)中没有发生这种情况。事实上,当对象在终结器队列中挂起时,可能会有一个OutOfMemoryError,其处理可以使更多的内存恢复。没有任何保证,最后确定运行的足够快,您的目的。这就是为什么你不应该依赖它。

票数 6
EN

Stack Overflow用户

发布于 2016-12-22 18:49:03

但是,如果这个“空闲”内存包含一个带有finalize方法的对象,该怎么办?GC不得不调用它,但我看不出它是如何知道已经无法访问的对象的。

假设我们使用CMS垃圾收集器。在第一阶段成功标记所有活动对象之后,它将再次扫描内存并删除所有已死对象。GC线程不直接为这些对象调用finalize方法。

在创建过程中,它们由JVM包装并添加到终结器队列中(请参见java.lang.ref.Finalizer.register(Object))。此队列在另一个线程(java.lang.ref.Finalizer.FinalizerThread)中处理,当没有对对象的引用时,将调用finalize方法。更多细节将在这篇博客文章中介绍。

如果是这样的话,拥有可完成的对象是否会使垃圾收集变得更昂贵,即使它们还活着?

正如您现在所看到的,大多数情况下,情况并非如此。

票数 3
EN

Stack Overflow用户

发布于 2016-12-22 18:42:33

当一个对象是关于finalise以获取垃圾收集时,调用方法。这意味着,当GC确定对象不再被引用时,它可以调用对象上的finalise方法。它不需要跟踪物体的最终结果。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41289671

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档