Finalizer being run while class still in use (escape analysis bug)
Luke Hutchison
luke.hutch at gmail.com
Wed Oct 10 09:39:37 UTC 2018
On Wed, Oct 10, 2018 at 3:06 AM Andrew Haley <aph at redhat.com> wrote:
> The problem with using finalizers is that finalizers may be run too
> soon (as here,) too late, or never. The "never" possibility really
> does happen: sometimes a generational collector moves objects to the
> old generation, and as long as there is little memory pressure only
> the young generations are collected. You may run out of file handles
> long before you run out of memory.
I know there are a lot of downsides to finalizers, and I have made it clear
in the documentation of my library that they should assign the object
concerned in a try-with-resources block. The finalizer is simply there to
clean up resources if the user neglects to follow this advice, which is
common in Scala, since it doesn't have try-with-resources, so the user has
to manually close the object in a "finally" block. I'm not as concerned
with the "may never be run" case, since that is really on the users of the
library. I'm more concerned about the "may be run while still in scope"
case, since that can break things in very surprising ways.
So given a class
class A {
void someMethod() {
try {
// ...
} finally {
Reference.reachabilityFence(this);
}
}
}
how is it that a call
new A().someMethod()
does not have a race condition between the "new A()" instance being invoked
and reachability analysis realizing that there is a "this" reference in the
finally block? Is it always true that there is an overlap between the
reference to the invocation target being held and the reference to "this"
in the method body being considered as reachable?
Or stated as the inverse, is it guaranteed that there will be no gap in
time (albeit infinitessimally small) between method invocation and the
running of the method in which there will be no reference to the "new A()"
object, where the finalizer could still be run?
On Wed, Oct 10, 2018 at 3:16 AM Andrew Haley <aph at redhat.com> wrote:
> > I believe that I did not misread the spec, and that this is covered
> > by the wording, "A reachable object is any object that can be
> > accessed in any potential continuing computation from any live
> > thread", since if a non-static method of an object is currently
> > running, that object not only "can be accessed" by a live thread, it
> > *is* currently being accessed by a live thread.
>
> No. Believe it or not, a live method does not constitute an access
> to an object. An object can die and be finalized even before one
> if its methods is entered.
>
That is highly surprising. This makes finalizers a lot less reliable and
more difficult to use than they could be.
Wouldn't it make sense to consider the invocation targets in the stack
during liveness analysis, so that out of the cases you gave, "finalizers
may be run too soon (as here,) too late, or never", at least the "too soon"
case is fixed?
More information about the jdk-dev
mailing list