Java GC如何调用finalize()方法? [英] How does Java GC call finalize() method?
问题描述
但是如果这个'free'内存包含一个带有 finalize
方法的对象呢? GC不得不称呼它,但我不知道它甚至无法知道无法再到达的对象。
我想GC可以跟踪所有'他们还活着的时候可以定型的物品。如果是这样,是否有可终结对象使垃圾收集更加昂贵,即使它们还活着? 考虑参考API 。
它为GC提供了一些特殊的语义参考,即弱,软和幻影参考。还有另一个非> public
类型的特殊引用,用于需要最终化的对象。
finalize()
方法(它不是垃圾收集器本身调用此方法)。换句话说,垃圾回收器从不处理完全不可达的对象。为了对可达性应用特殊的语义,必须能够访问引用对象,因此可以通过到达引用。在终结者可达性的情况下, Finalizer <>的实例时,调用Finalize.register 。 / code>,依次为 FinalReference
和在它的构造函数中,它调用一个 add( )
方法,它将引用插入到全局链表中。因此,所有这些 FinalReference
实例都可以通过该列表到达,直到实际完成发生。
由于 FinalReference
将在对象实例化时创建,如果它的类声明了一个非平凡的 finalize()
方法,那么已经有了一些开销,由于有终结要求,即使对象还没有收集。
另一个问题是由终结线程处理的对象可以通过该线程到达甚至可能会转义,这取决于 finalize()
方法的作用。但下一次,这个对象变得无法访问,特殊的引用对象不再存在,所以它可以像其他任何不可达对象一样对待。
这只会是一个性能问题,如果内存非常低,并且必须先执行下一个垃圾收集才能最终收回该对象。但是这在参考实现(又名HotSpot或OpenJDK)中不会发生。实际上,当终结器队列中的对象处于挂起状态时,可能有一个 OutOfMemoryError
,其处理可能会使内存更多地被回收。没有保证终结运行足够快,因为你的目的。这就是为什么你不应该依赖它。
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.
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.
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?
Consider the Reference API.
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.
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).
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.
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.
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.
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.
这篇关于Java GC如何调用finalize()方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!