[gclist] Finalization and death notices

Boehm, Hans hans_boehm@hp.com
Tue, 9 Oct 2001 10:57:41 -0700


I think that some of what we're really talking about here is the choice
between three alternatives:

1) The collector directly runs finalizers from whichever thread happened to
allocate and invoke the collector.  This is common in early Java
implementations, but fundamentally broken.  It leads to intermittent
deadlocks and/or multiple threads in the same monitor.  Let's ignore this
alternative.  (Such a facility can sometimes be used to implement a
reasonable one.  But if it's there it shouldn't be exposed to the user.)

2) The collector enqueues objects ready for finalization, and the finalizers
are run in a different thread.  This is what Java essentially requires for
"finalizers".

3) (near-death notice) The collector enqueues finalizable objects, and the
client decides when to run the finalizers.  This is essentially the Java2
java.lang.ref.PhantomReference approach.

Our collector basically does (1) or (3), with the intent that a higher layer
would export something like (2).  It seems to me that (2) and (3) each have
advantages.  But the difference isn't crucial since each can be used to
simulate the other.  It seems to me they are both fully safe, except for
denial-of-service attacks, which we currently can't handle anyway.  For
single-threaded applications, only (3) is usable, though still a bit
unpleasant, since the client needs to poll regularly.

In a multithreaded environment, I would probably still marginally prefer (2)
as the standard user-visible model.  Otherwise it seems to me that the only
way to avoid regular polling all through the client code is to create a
finalization thread per module.  In most cases that seems unnecessarily
resource intensive.

But certainly either (2) or (3) work fine.  This I think we basically have 2
equivalent plus one broken alternative.

Hans


> From: Charles Fiterman [mailto:cef@geodesic.com]
> At 05:13 PM 10/9/01 +0100, you wrote:
> >It seems to me that finalization and death notices are trivially
> >equivalent in power (in the sense that either can be readily
> >implemented on top of the other).  If I'm wrong it's because I'm just
> >guessing the semantics of death notices.  Can you tell me the real
> >semantics of death notices?
> 
> Near death notices can do anything finalization can do but 
> are stronger and
> safer. They are stronger because the user controls the 
> context of their
> use. Thus near death notices can throw exceptions, use locks in a
> coordinated way, use thread local storage etc. Also the user 
> can traverse
> unset near death notices. They are safer because the 
> collector is never
> told to run user code. I suppose the user could use a 
> finalizer to create a
> near death notice matching the stregnth but the safty issue 
> would remain.
> 
> The semantics of a near death notice is the user goes to the 
> collector with
> a structure having the address of a double linked list and a 
> weak reference
> to an object. When the object is near death the weak 
> reference becomes a
> strong reference and the structure is unlinked from the 
> double linked list
> its on and linked to its designated list. The user is responsible for
> dealing with the list as he will.
> 
> Death notices are more efficient than near death notices and 
> weaker. They
> behave like a near death notice except the weak reference is 
> zeroed not
> turned into a strong reference and the object is actually 
> blown away. Thus
> storage is cleared faster.
>