[gclist] What does a garbage collector do about

David Chase chase@world.std.com
Sat, 27 Jul 2002 17:33:30 -0400


At 6:29 PM +0100 7/27/02, Michael Mounteney wrote:
>``4.  You should also consider whether you should be using destructors if you
>are using exceptions to handle OS and other environment errors.
>
>``To extend his argument:  if exceptions raised by destructors are a bad
>thing, then exceptions raised asynchronously by a garbage collector are
>terrible:  the context of the exception will be lost, and the software
>basically has the choice between terminating and ignoring the problem.  The
>only solution is an explicitly-called finalisation method that releases all
>the object's resources.''

Not sure I agree.  First, you are correct that it is simply not
feasible to throw an exception out of a finalizer into some
mystery context; therefore, the default behavior (in Java, at
least) is to silently swallow the exception.  The finalizers in
the Java I/O system are a backstop -- if the file is already
closed (by the author of a program containing "robust handling
code") then the finalizer does not re-close the file and exceptions
are not an issue.  However, if it happens that a file is not
closed before all references are dropped, it seems unwise to
simply leak the file descriptor.  999 times out of 1000, that
file could have been closed without error, and not closing it
is probably more wrong than closing it and discarding the
occasional error.

Another alternative if you care about errors but expect to use
finalizers sometimes, is to simply use a subtype with a
wrapped finalizer:

class FooStream extends FileInputStream {
   // delegate everything
   protected void finalize() {
     try {
        super.finalize();
     } catch (Throwable th) {
       // log it to a thread that cares.
     }
   }
}

I don't think this is an option in C++ (since the superclass
destructor cannot throw an exception, nor you can talk about
"threads" in a standard-conforming manner), but maybe this
says more about C++ than it does about finalization.

So, given that there are three ways to deal with this "problem"

a) ignore it, since the client didn't care
b) don't get in the way of a client that does care
c) provide the means to log errors in finalizers

I don't think it is much of a problem.  If you were designing
a language from scratch, there are even more possibilities for
dealing with this -- for instance, the user could supply the
thread for running finalizers, and thus have control of them.

David Chase