Finalizer being run while class still in use (escape analysis bug)
david.lloyd at redhat.com
Wed Oct 10 20:19:27 UTC 2018
On Wed, Oct 10, 2018 at 2:57 PM Luke Hutchison <luke.hutch at gmail.com> wrote:
> On Wed, Oct 10, 2018 at 9:53 AM Kim Barrett <kim.barrett at oracle.com> wrote:
> > Finalization was deprecated in JDK 9 (*). There's an ongoing (though
> > progressing slowly) process of eliminating its usage in the JDK.
> > Sometime after that it may go away entirely, or perhaps require some
> > sort of explicit opt-in, making it possible to eliminate various GC
> > overheads associated with it.
> It would be a much better API contract to state that "if you override
> finalize(), some code optimizations may not kick in" rather than "if you
> override finalize(), things will almost certainly break, and you get to
> keep all the pieces".
Unfortunately this doesn't really make a difference: finalize() is
broken for reasons beyond the "early" cleanup problem, and the "early"
cleanup problem actually also applies equally to PhantomReference- and
Cleaner-based solutions, as well as other *Reference types. This
email thread may have obscured the fact that the two issues are really
One thing that always (safely) forces references to stay alive (apart
from reachabilityFence(), which is the best solution) is calling
either a non-static native method on that object, or otherwise passing
the reference to a native method as a parameter or part of the graph
that is reachable from a parameter. Since finalizers often deal with
native resources, sometimes this prevents the problem from appearing
in the first place.
Another easy-ish solution is synchronization. If your impactful
methods execute under a synchronized block, and your finalize() or
cleanup operations also operates under the same block, then premature
cleanup cannot happen. Obviously you can't use the object itself in
the PhantomReference/Cleaner case otherwise the object will never be
As Andrew said, you could make your own fence using a volatile field
write/read. I think it might be enough to write the field at the
fence point and read the field in finalize(), though a JMM ace would
have to confirm that.
More information about the jdk-dev