Java GC如何调用finalize()方法? [英] How does Java GC call finalize() method?

查看:98
本文介绍了Java GC如何调用finalize()方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

据我所知,GC从一些初始对象(堆栈,静态对象)开始,并递归地遍历它,从而构建可达对象的图形。然后它将这些对象占用的内存标记为占用,并假定所有剩余的内存空闲。

但是如果这个'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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆