Sat, 12 Apr 1997 10:05:01 -0700
Since we seem to be delving into a discussion of what it means to be
"weak-for-finalization", it's important to keep a couple of things in mind:
1. This is not an essential facility, though I think it can facilitate
discussion. You can get the same affect by splitting a finalizable object A
into two objects A' and A''. A' points to A''. A'' holds the data needed for
finalization. A' holds everything else. Only A'' is finalizable.
Finalization can't possibly consider the pointers in A', which can be
previously reclaimed, even if it is in a cycle.
2. I've never seen a case in which the details of this facility mattered. I've
only seen something like 2 cases in which there was a problem with finalization
cycles. I believe they could all have been trivially resolved with any
reasonable version of this facility, or with the above technique.
On Apr 12, 5:02am, Fergus Henderson wrote:
> I had a look at the Boehm collector's interface for weak pointers,
> namely `GC_general_register_disappearing_link(&ptr, &obj)', which
> sets `ptr' to null when `obj' is known to be unreachable. This is not
> quite what I had in mind for "weak-for-finalization" pointers,
> which I defined as "(pointers which are ignored when determining
> finalization order)". Weak-for-finalization pointers in an object
> could be cleared just before calling the object's finalizer, but they
> should not be cleared any earlier. If the collector clears such
> pointers all at once after a GC before invoking any finalizers, that
> could cause problems. It would mean that if you are finalizing say A,
> which has a (strong) pointer to B, which has a (strong) pointer to C,
> then the weak-for-finalizations pointers in object C may be cleared
> before A's finalizer is executed. That is a problem because A's
> finalizer may call a method in B which calls a (non-finalizer) method
> in C which depends on C's weak-for-finalization pointers.
> So I guess `GC_general_register_disappearing_link()' can only be used
> for weak pointers, not for "weak-for-finalization" pointers. Oh well.
Let's say we have (ASCII diagram, dotted is weak for finalization)
A ----> B ----> C ......> D
A, C, and D are finalizable. D must be finalized first. Then A is finalized.
If the weak link has not been cleared at this point, then A's finalizer can
indirectly access D, which is no longer in a safe state.
To get this right in the general case, you need to have information in the
interface as to what operation can still be performed after an object has been
initially unreachable. Only some of C's operations, and hence some of B's
operations are available to finalizers. This is indeed unpleasant. It's the
same kind of global information you need in Carl's scheme. But there are
several mitigating factors:
1. I don't know of any cases in which this really involves any complexity. The
alternative schemes require a fairly general treatment whenever a finalizer
invokes procedure on another object, which is relatively frequent.
2. If I mess up, I either get a leak, or possibly a nil pointer dereference
(though I've never actually seen that case, and it can't arise in the object
splitting scheme). With user-defined finalization, I end up accessing a
deallocated resource, which is often not easily diagnosable, and can
conceivably result in undiagnosed incorrect output.
I have in fact missed something like Fergus' suggested alternate semantics for
conventional weak pointers. You sometimes want those to stay around until an
object has actually been finalized. But that can be implemented on top of the
current (unsafe) finalization interface.