Why is finalize wrong?

Stanimir Simeonoff stanimir at riflexo.com
Wed Sep 3 11:48:40 UTC 2014


Hi Andrew,


On Wed, Sep 3, 2014 at 12:58 PM, Andrew Haley <aph at redhat.com> wrote:

> On 03/09/14 01:15, Stanimir Simeonoff wrote:
>
> > Like David Lloyd mentioned finalize() can be invoked concurrently to
> > some methods (if there is no reachability to 'this'). OTOH I see
> > finalize useful for managing native resources mostly and possibly
> > stopping (signaling) threads left unmanaged. In that particular case
> > synchronization is a must, so it comes naturally.
>
> But finalize isn't useful for managing native resources because
> finalizers may or may not run, as you note.  People will test their
> programs with one implementation then discover, when their programs
> are deployed, that they sometimes mysteriously fail.  In particular,
> you might run out of file handles.
>
> I meant cleaning up rather than managing per se. To make it clear:
finalization is no substitute for proper lifecycle - anything that has
open() should have a following up close(), otherwise it's a bug.
Finalization still helps as safenet vs leaving native resources totally
unallocated and leaking. Yet, finalizers have to run somehow since the
direct (and mapped) buffers very heavily rely on them. The direct/mapped
buffers are ones that don't have proper lifecycle, esp. the mapped ones
The latter don't offer munmap.
I believe the java.nio.Bits still includes a notorious call in a

static void reserveMemory(long size, int cap) {
//check if above the direct memory threashold and...
        System.gc();
        try {
            Thread.sleep(100);
        } catch (InterruptedException x) {
            // Restore interrupt status
            Thread.currentThread().interrupt();
        }
}
in an attempt to cope with the lack of proper and timely finalization.
Prior the fix the OOM when using DirectBuffers was quite guaranteed unless
pooling the buffers on your own.
On a flip note, I think it's kind of a bug as it has to manually call run
System.runFinalization() prior throwing the OOM, but it opts to sleep 100ms
instead.

If the finalizers don't run prior the process termination, that's ok as the
OS should be able to clean up any native resources allocated on its own.
However finalizers not running is not that different from a weak/phantom
reference not being enqueued, practically the odds are quite the same. The
impl. of the finalization is actually a high priority dedicated thread that
processes a ReferenceQueue.



> As Jarolsav put it, "I don't think this is explainable to regular Java
> developers."  As David Lloyd put it, "If you still think that finalize
> is a good idea, given that it's basically defective *and* there is
> almost always a better solution, then I will be quite astounded."  As
> I put it, "finalize is broken."
>
>
I'd not say "broken", as it works exactly as specified. Still I utterly
agree it requires pretty deep knowledge on the inner works to make it
somewhat useful.

Stanimir



More information about the core-libs-dev mailing list