[gclist] Finalization and death notices

Kerns, Bob Bob.Kerns@firepond.com
Tue, 9 Oct 2001 15:02:22 -0500


You need to distinguish between death notices, and near-death notices.
They're not the same thing.

I would agree that near-death notices can be used to implement finalizers,
and vice versa.

This is *not true* of death notices, as I understand them. When a death
notice is delivered, the object no longer exists.

My claim is that this is enough to implement all the *useful*
characteristics of finalizers, without any of the not-so-good
characteristics:
1) No revivification
2) No issues about whether to re-run the finalizer when a revivified object
again becomes unused.

Another advantage of death notices is that --with no cooperation from the
object required-- any client can request notification. This is something
that finalizers don't give you, and can be used to do things like implement
structures like weak hash tables -- except you can directly do much more
general things, like for example remove entries from a 3D region-query
database. To do the equivalent in Java, you'd have to add the code to
Object's finalize() method, or more practically, have a weak hash table on
the side that you periodically check for things to remove.

BTW, this last advantage is shared by near-death notices. Yes, you *can* it
with finalizers, but you can't do it cleanly, with delivery at the point
where the GC discovers the object is unreferenced. (There's no defined
semantic point at which the GC discovers this, so this is only a semantic
difference in degree, not in kind, but clearly, prompt delivery is better
than tardy delivery).

-----Original Message-----
From: Boehm, Hans [mailto:hans_boehm@hp.com]
Sent: Tuesday, October 09, 2001 10:58 AM
To: 'Charles Fiterman'; gclist@iecc.com
Subject: Re: [gclist] Finalization and death notices 


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.
>