java - Java GC 如何调用 finalize() 方法?

标签 java garbage-collection jvm

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

但是如果这个“空闲”内存包含一个带有 finalize 的对象呢?方法? GC 必须调用它,但我看不出它是如何知道无法再访问的对象的。

我想 GC 可以在所有“可终结”对象还活着时跟踪它们。如果是这样,即使它们还活着,拥有可终结对象是否会使垃圾收集更加昂贵?

最佳答案

考虑 Reference API .

它提供了一些对 GC 具有特殊语义的引用,即 Weak、Soft 和 Phantom 引用。还有另一个非 public特殊引用类型,用于需要终结的对象。

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

换句话说,垃圾收集器从不在这里处理完全不可达的对象。要将特殊语义应用于可达性,引用对象必须是可达的,因此可以通过该引用到达所指对象。在终结器可达性的情况下, Finalizer.register 在创建对象时调用并创建 Finalizer 的实例反过来,是 FinalReference 的子类, 和 right in its constructor ,它调用 add()将引用插入全局链表的方法。所以所有这些FinalReference实例可以通过该列表访问,直到实际完成。

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

另一个问题是由终结器线程处理的对象可由该线程访问,甚至可能逃逸,具体取决于 finalize()方法。但是下一次,这个对象变得不可达,特殊引用对象不再存在,所以它可以像任何其他不可达的对象一样对待。

如果内存非常低并且必须更早执行下一次垃圾收集以最终回收该对象,这只会是一个性能问题。但这不会发生在引用实现(又名“HotSpot”或“OpenJDK”)中。事实上,可能有一个 OutOfMemoryError当对象在终结器队列中挂起时,其处理可以使更多内存可回收。无法保证最终确定的运行速度足以满足您的目的。这就是为什么你不应该依赖它。

关于java - Java GC 如何调用 finalize() 方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41289671/

相关文章:

java - 为什么 jvm 在没有人真正需要的时候从 jar 中加载类?

java - 如何使用 spring boot 应用程序从 Rest API 返回 html

内存压力

java - jvm 垃圾收集太少 - clojure

java - 当出现内存不足错误时自动重启tomcat

algorithm - 在 Java 中创建一个对象需要多少个 CPU 周期?

java - 为什么 SQL 中的 CHAR(1) 占用 1 个字节,而 java 中的 char 占用 2 个字节?

java - 评估业务规则引擎的标准

java - 新关键字和垃圾收集

java - JVM是否保证缓存非 volatile 变量?