[gclist] Finalization and death notices

Boehm, Hans hans_boehm@hp.com
Mon, 8 Oct 2001 10:44:24 -0700

> From: Greg Colvin [mailto:gcolvin@us.oracle.com]
> From: Boehm, Hans <hans_boehm@hp.com>
> > 
> > > From: Greg Colvin
> > > It wouldn't bother me if optaining locks in
> > > cleanup functions were also unsafe.  Different restrictions might
> > > be appropriate in other languages, but the idea that the 
> only thing
> > > a cleanup function should do is release resources seems 
> appropriate
> > > to me.
> > The problem is that releasing resources often involves 
> putting them back
> > into a global pool for reallocation.  If the pool is 
> maintained inside the
> > user program, that generally requires a lock.  (If it's a 
> kernel resource,
> > the issues doesn't arise, since the lock can't be acquired 
> by user code.)
> Ultimately, it seems, all resources are kernel resources.
Yes, but it doesn't helps if any of the management is done at user level,
e.g. because you are caching the resource, or if it's being managed by a
third party library which requires that you call its destructor functions.
> ...
> This seems to come back to the same old debate about GC for
> C++ -- to finalize or not to finalize, and if so how?  We
> go round and round looking for the "right" way, whereas java
> just went ahead and did it wrong, and users soon learned
> that finalizers were nearly useless.  And lacking destructors
> they learned to manage resources with finally clauses.
If you can manage a resource with finally clauses that's great, and you
shouldn't be using finalizers for those resources.  Finalizers should be
used only for resources whose useful lifetime doesn't end at a clearly
defined point in the program.  In my experience that makes them rarely
useful, but they are absolutely essential when you do need them.  Usually
the only way to get by without them is to essentially redo all the work
already being done by the collector.

In my opinion, Java finalizers, as defined in the language spec, are not
useless.  The specification has some flaws (lack of ordering, excessive
complexity for the many weak reference types), but I don't think those are
anywhere near fatal.  At least early implementations had some
bugs/misfeatures that were probably fatal:

1) Finalizers were often called directly form the collector in the
allocating thread, causing intermittent failures of various kinds.

2) In some implementations, the collector avoided running finalizers as long
as possible.  The finalization mechanism was implemented so that it could be
used directly to implement web page caching in a browser, which made it
close to useless for anything else.

I don't think it's fair to argue that this is a useless construct because of
bugs in a few implementations.  My impression from Cedar and Modula 3
programmers is that this was universally viewed as an essential, though
rarely used facility.

I think it's fairly typical to find one use of finalization in 50,000 lines
of code.  These are not C++ destructors.  They are not intended to be nearly
as ubiquitous as the finalization discussion on this list.