Java GC 是如何调用 finalize() 方法的?

2022-01-16 00:00:00 jvm garbage-collection java

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

As far as I understand, GC starts with some set of initial objects (stack, static objects) and recursively traverses it building a graph of reachable objects. Then it marks the memory taken by these objects as occupied and assumes all the rest of the memory free.

但是如果这个空闲"内存包含一个带有 finalize 方法的对象呢?GC 必须调用它,但我不明白它是如何知道不再可访问的对象的.

But what if this 'free' memory contains an object with finalize method? GC has to call it, but I don't see how it can even know about objects that aren't reachable anymore.

我想 GC 可以在所有可终结"对象还活着的时候跟踪它们.如果是这样,具有可终结对象是否会使垃圾收集更加昂贵,即使它们仍然存在?

I suppose GC can keep track of all 'finalizable' objects while they are alive. If so, does having finalizable objects make garbage collecting more expensive even when they are still alive?

推荐答案

考虑 参考 API.

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

It offers some references with special semantics to the GC, i.e Weak, Soft, and Phantom references. There’s simply another non-public type of special reference, for objects needing finalization.

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

Now, when the garbage collector traverses the object graph and encounters such a special reference object, it will not mark objects reachable through this reference as strongly reachable, but reachable with the special semantics. So if an object is only finalizer-reachable, the reference will be enqueued, so that one (or one of the) finalizer thread(s) can poll the queue and execute the finalize() method (it’s not the garbage collector itself calling this method).

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

In other words, the garbage collector never processes entirely unreachable objects here. To apply a special semantic to the reachability, the reference object must be reachable, so the referent can be reached through that reference. In case of finalizer-reachability, Finalizer.register is called when an object is created and it creates an instance of Finalizer in turn, a subclass of FinalReference, and right in its constructor, it calls an add() method which will insert the reference into a global linked list. So all these FinalReference instances are reachable through that list until an actual finalization happens.

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

Since this FinalReference will be created right on the instantiation of the object, if its class declares a non-trivial finalize() method, there is already some overhead due to having a finalization requirement, even if the object has not collected yet.

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

The other issue is that an object processed by a finalizer thread is reachable by that thread and might even escape, depending on what the finalize() method does. But the next time, this object becomes unreachable, the special reference object does not exist anymore, so it can be treated like any other unreachable object.

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

This would only be a performance issue, if memory is very low and the next garbage collection had to be performed earlier to eventually reclaim that object. But this doesn’t happen in the reference implementation (aka "HotSpot" or "OpenJDK"). In fact, there could be an OutOfMemoryError while objects are pending in the finalizer queue, whose processing could make more memory reclaimable. There is no guaranty that finalization runs fast enough for you’re purposes. That’s why you should not rely on it.

相关文章