问题
I'm reading this article and I can't really understand how the finalizable objects (objects which override the finalize
method) takes at least 2 GC cycles before it can be reclaimed.
It takes at least two garbage collection cycles (in the best case) before a finalizeable object can be reclaimed.
Can someone also explain in detail how is it possible for a finalizable object to take more than one GC cycle for reclamation?
My logical argument is that when we override finalize method, the runtime will have to register this object with the garbage-collector (so that GC can call finalize
of this object, which makes me think that GC will have reference to all the finalizable objects). And for this, GC will have to keep a strong reference to the finalizable object. If that is the case then how this object became a candidate for reclamation by GC in the first place? I reach a contradiction by this theory.
PS: I understand that overriding finalize
is not the recommended approach and this method is deprecated since Java 9.
回答1:
You are right in that the garbage collector needs a reference to finalizable objects. Of course, this particular reference must not be considered when deciding whether the object is still reachable before the finalization. This implies special knowledge about the nature of this reference to the garbage collector.
When the garbage collector determines that an object is eligible for finalization, the finalizer will run, which implies that the object becomes strongly reachable again, at least as long as the finalizer is executed. After its finalization, the object must become unreachable again and this must be detected, before the object’s memory can be reclaimed. That’s why it takes at least two garbage collection cycles.
In case of the widely used Hotspot/OpenJDK environment (and likely also in IBM’s JVM), this is implemented by creating an instance of a special, non-public subclass of Reference, a Finalizer, right when an object, whose class has a non-trivial finalize()
method, is created. Like with weak & soft references, these references are enqueued by the garbage collector when no strong reference to the referent exist, but they are not cleared, so the finalizer thread can read the object, making it strongly reachable again for the finalization. At this point, the Finalizer
is cleared, but also not referenced anymore, so it would get collected like an ordinary object anyway, so by the next time the referent becomes unreachable, no special reference to it exists anymore.
For objects whose class has a “trivial finalizer”, i.e. the finalize()
method inherited by java.lang.Object
or an empty finalize()
method, the JVM will take a short-cut and not create the Finalizer
instance in the first place, so you could say, these objects, which make the majority of all objects, behave as if their finalizer did already run, right from the start.
回答2:
Though you got your answer (which is absolutely correct), I want to add a small-ish addendum here. In general, references are of two types : strong and weak. Weak References are WeakReference/SoftReference/PhantomReference
and Finalizer
(s).
When a certain GC cycle traverses the heap graph and sees one of these weak references
, it treats it in a special way. When it first encounters a dead finalizer reference (let's consider this being the first GC cycle), it has to resurrect the instance. finalize
is an instance method, and it needs an actual instance to be invoked. So a GC first saw that this Object is dead, only to revive it moments later, to be able to call finalize
on it. Once it calls that method on it, it marks the fact that it has already been called; so when the next cycle happens, it can be actually be GC-ed.
It would be incorrect to call this the second
GC.
For example G1GC
does partial clean-up of the heap (young and mixed), so it might not even capture this reference in the next cycle. It might not fall under its radar, as simple as that.
Other GCs, like Shenandoah
, have flags that control on which iteration to handle these special references (ShenandoahRefProcFrequency
, 5 by default).
So indeed there is a need for two
cycles, but they do not have to be subsequent.
来源:https://stackoverflow.com/questions/53791900/how-finalizable-objects-takes-at-least-2-garbage-collection-cycles-before-it-can