[gclist] Guardians

Hans Boehm boehm@hoh.mti.sgi.com
Thu, 10 Apr 1997 15:41:44 -0700

On Apr 10,  3:29pm, Carl Bruggeman wrote:
> Subject: Re: [gclist] Guardians
> > There are 2 disadvantages in letting the programm choose the finalization
> > ordering:
> >
> > 1) It's more work.  Getting it wrong can be dangerous if finalizers manage
> > explicitly allocated memory.
> It doesn't have to be more work for the programmer. ...
I don't have any problems with the queueing model.  I think that's the
right solution.

> The only case where it might be more work is when the
> programmer does want to do finalization in a particular.  This case is
> trivial in the topological finalization model because you always get
> topological ordering, which either works or doesn't work.
I think this is the heart of the disagreement.  Topological ordering
relies on the assumption that if something is accessible from the finalizer, it
may be referenced, and thus should be preserved, i.e. not finalized.  A
slightly different flavor of this assumption is already inherent in any form of
garbage collection.  It fails occasionally, hence the discussion of clearing
pointers, etc.  But it seems to be a winning assumption 99% of the time.  Why
do we believe it for garbage collection and not finalization.

> Since there is equal danger in getting finalizer code wrong for either
> system, I assume that you are indicating that there is additional risk
> that the programmer will never query a guardian, while the collector
> can ensure that finalizers are always run.
I don't have any problem with the queueing model.  My collector doesn't do that
by default, but it's easy to add that mechanism, and some of it's clients do.

> I generally favor
> erring on the side of putting power in the hands of programmers rather
> than tying their hands to save them from themselves.
So do I, up to a point.  I haven't been convinced that being able to see
post-finalized objects (without finalizer cooperation to make them accessible
again) is any more of a useful feature than being able to look at deallocated
storage, which I could generally do without.  If the finalizer deallocates
malloc'ed objects, they are THE SAME.

The default behavior should be to err on the side of safety.  In the presence
of topologically ordered finalization, you (on rare occasions) do need a
mechanism that corresponds to explicitly clearing pointers.  That allows you to
use other orderings when you have to.  (In the version implemented in our
collector, you still don't see post-finalized objects, since the pointers in
question actually do disappear.)

> > 2) It relies on global information, which the programmer shouldn't need to
> > know. If my finalizer for type A objects invokes a method on a type B
> it
> > references, I need to take special precautions if and only if type B
> > also require finalization.  I shouldn't have to know that.  If B is a
> er
> > string represented as a cord (see my previous message), I would have to
> > whether a string I use happened to be built out of a sufficiently long
> > and whether any of those characters survived editing, something I really
> t
> > want to know this.  The garbage collector already determines the righ kind
> > global information.
> Using guardians I would simply register type A objects with one guardian
> and type B objects with another guardian, and always finalize all objects
> on the type A guardian before finalizing objects on a type B guardian.
> The information is not global; it can be limited to the implementation of
> the A and B types.
Yes, but A and B may have been written by different people.  The implementor of
A (some random user) shouldn't need to know about the implementation of B
(strings).  In fact B may refer to C, which refers to D, which requires
finalization.  The necessary information is global.  Equivalently, you have to
widen interface definitions to mention finalization constraints.  (This may
also be true in the toplogical case in much rarer cases.  The failure mode is
more benign.)

I also don't quire understand how your solution would work.  The type B
finalization can trigger another collection, enqueuing more type A and B
objects.  The newly enqueued type B objects will then be finalized before
theire corresponding type A objects.

You also seem to be relying on the fact that a type B object will not be found
inaccessible before its corresponding type A object.  Since A points to B,
that's often true.  I'm not convinced it's true for our garbage collector.  I
can certainly contrive collectors for which it's false.

> You appear most concerned with C++ applications where the collector's
> topological ordering is _one_ correct finalization order and you wish
> to preserve and utilize this ordering information that the collector
> derives.  I (and perhaps a few others) believe that topological
> ordering is too restrictive for general purpose finalization and that
> other correct finalization orders are simple enough to derive and
> implement without being an undue burden on the programmer.

This is the claim I don't understand.  And I still haven't found an example.
There are millions of lines of code written with topologically ordered
finalization.  The only known deficiency is that you would on rare occasion
like to ignore some pointers for finalization ordering.


Hans-Juergen Boehm