----- Original Message -----
From: "Greg Ewing" <email@example.com>
Sent: Saturday, March 28, 2009 5:32:27 PM GMT -06:00 US/Canada Central
Subject: Re: [Python-ideas] python-like garbage collector & workaround
> I'm considering a workaround that performs GC in two steps. First, it
> requests the objects to drop their references that participate in the
> cycle. Then, it enqueues the decref'ed object for an unnested
I don't see how that solves anything. The problem is that
the destructors might depend on other objects in the cycle
that have already been deallocated. Deferring the calling
of the destructors doesn't help with that.
The only thing that will help is decoupling the destructor
from the object being destroyed. You can do that now by
storing a weak reference to the object with the destructor
as a callback. But the destructor needs to be designed so
that it can work without holding any reference to the
object being destroyed, since it will no longer exist by
the time the destructor is called.
Nice response time.
> Deferring the calling of the destructors doesn't help with that.
beg to differ. There is a complex example in the test code at the
address. Here is a simple one. 'A' has a reference to 'B' and 'B' has
a reference to 'A'. They both need to call each other's methods during
their respective finalizations.
1. Ref counts: A-1, B-1
2. Request A to drop ref. to B.
3. Ref counts: A-1, B-0.
4. Finalize & deallocate B.
5. ... B drops ref. to A
6. Ref counts: A-0
7. Finalize & deallocate A.
performs its final call to 'B' in step 2, still having a reference to
it. It empties the attribute of its own that refers to B. 'B's
reference count goes to 0. 'B' performs its final call to 'A' in step
5, still having a reference to it. 'A' still has control of its
fields, and can make remaining subordinate calls if necessary. 'B'
releases its reference to 'A', and 'A's reference count goes to zero.
'B' is deallocated. 'A' performs its finalization, and should check
its field to see if it still has the reference to B. If it did, it
would perform the call in step 2. In this case, it doesn't, and it can
keep a record of the fact that it already made that final call. 'A's
finalizer exits without any calls to 'B', because the field that held
its reference to 'B' is clear. 'A' is deallocated.
> But the destructor needs to be designed so
> that it can work without holding any reference to the
> object being destroyed
want to give 'A' control of that. To accomplish this, I bring it to
A's attention the fact that it has left reachability, /and/ is in a
cycle with B. It can perform its normal finalization at this time and
maintain its consistency of state.
I believe it solves the problem of failing to call the destructor at all, but I may have just shirked it. Will it work?