[gclist] Timeliness of finalization

Hans Boehm boehm@hoh.mti.sgi.com
Sat, 29 Mar 1997 12:21:35 -0800

On Mar 28,  6:10pm, Giuliano Carlini wrote:
> What do you think about running finalizers at exit for non OS objects? It
seems that these
> must be run at exit. If I create a service, why should I have to support two
different ways to
> release objects. One which occurs durring normal execution, and one to
optimize process
> exit? I suspect that usually this would be a misguided microoptimation that
saves very
> little time. Especially when getting code to run at process exit is typically
> unportable pain in the backside.
> Consider C++ streams which buffer output. These clearly must be finalized at
exit. Seems
> like running finalizers at exit is just the ticket to do this. C++ runtimes
> manage to do this, but the compiler vendors stoop to some ugly hacks to get
it done.
In some simple cases finalization actions are the same as exit actions.  It
might make sense to provide an interface that lets you do both conveniently.
 (The counterargument is that finalization probably isn't used enough to make
convenience a big issue.) But the two are often not the same, for several

1) Exit actions must be able to run with global variables (or static members)
already finalized.  Thus they can rely on very little of the global state still
being intact.  (Charles' proposal would help this a bit, but the added
constraints are still there.)  In general, I can use an exit action as a
finalizer.  But many things work as finalizers and not exit actions.

If I finalize in topological order, the difference gets larger, since I can't
possibly do that at process exit in the presence of cycles.  If I drop the
topological ordering constraint for objects finalized at exit, then flushing
buffers doesn't work unless I'm careful not to close files at process exit.
I have the same problem with Java-line unordered finalization if buffered
streams squirrel away file handles they need in a global data structure.  At
finalization time, the handle is guaranteed to be around.  At process exit, it
may have been closed.

2) Unnecessary finalization at process exit can be a big deal.  I've had to
deal with (nonGC) C programs that insist on deallocating everything at process
exit.  It's really annoying to type quit at a program you hadn't been actively
using, and then have to wait several seconds (or longer) for the disk to finish
rattling while it writes new free list links into all those objects that
haven't been touched for a day, just before it throws the pages away.  You get
the same problem in, say, a garbage collected Java program if finalizers
deallocate memory allocated by C routines (probably the dynamically most common
use of finalizers?).

3) It occasionally might make sense to have finalizers that hang onto existing
resources and data structure for recycling instead of returning them.  (I think
there were one or two instances of this in Cedar.)  For example, one might hang
onto the buffers associated with C++ streams.  This is useless on process exit,
and it may be unsafe because of the first point (the buffer pool may have been


Hans-Juergen Boehm