[gclist] What does a garbage collector do about

David Chase chase@world.std.com
Sun, 28 Jul 2002 14:28:30 -0400


At 11:34 AM -0400 7/28/02, Greg Hudson wrote:
>On Sat, 2002-07-27 at 17:33, David Chase wrote:
>>  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.
>
>This kind of reasoning tends to encourage code which only works 999 out
>of 1000 times.  A leaked file descriptor is more likely to be noticed
>than a bug which only manifests when, say, you're using AFS and your
>tokens expire while you have a file open for writing.

I am looking at this from the POV of someone providing libraries
to clients.  If someone doesn't explicitly close the file, whatever
might have gone bad on the close, is still out there.  The close is
just the bearer of the bad news, and the problem was not avolded by
not doing the close.  This problem is inherited from modern operating
systems -- if your process exits with files not-yet-closed, how are
things any different?

In the case that you describe, I think that the AFS file objects
should contain enough state to get new tokens and get the job
done, if this is important.  A failure on close in a finalizer
is not appreciably worse than a failure on close in code that
operates (generically) on "files".  The generic code is just
as much in the dark.

Or, if no recovery is possible, then the finalizer should indeed
explode.  If you are writing a program that might need to work with
such files in the future, then follow my suggestion for the streams
and readers, and provide a bug-checking finalizer in a subclass.

>Of course, my reasoning suggests that file objects should have
>destructors which abort the program if the file hasn't been closed, to
>make it most likely that the bug will be noticed early.  So perhaps this
>isn't an argument against finalizers after all, just an argument that
>finalizers should be restricted to invariant-checking.

Why not simply provide tools for determining when "bad things"
happen, if it is cheap to do so?  (In this case, it is.)
People who need this can use the tools, the rest of the world
can go on being the approximate slobs that they are.

>This is an interesting possibility, but usually a separate thread
>doesn't have the context to know what to do about a finalizer error.  If
>you have trouble closing a file, it often means you have to gracefully
>abort the operation you were doing at the time; it requires a lot of
>extra state for the separate thread to know what that is.

Two answers:

- subclass the object, add necessary state, OR
- for some operations, this is indeed a bug, so people writing such
   programs should exercise extra care.  They can either do this by
   subclassing the objects in question to report errors in finalizers,
   or they can make use of tools that monitor use of finalizers.

>Also, papering over an issue like this with multithreaded programming is
>making a fairly big assumption--that multithreaded programming is a
>viable model for maintainable code.  In my experience, that assertion is
>unproven at best.

I think it is the best of the bad models currently available.  It replaces
atrocities like signal handlers preempting the current thread, wherever
it happens to be.  I think Java is too low level, but the abstractions
needed here (shared queues) don't require Java's low level approach.

What alternative do you propose?

David Chase