
----- Original Message ----- From: "Greg Ewing" < greg.ewing@canterbury.ac.nz > To: castironpi-ng@comcast.net Cc: Python-ideas@python.org Sent: Saturday, March 28, 2009 5:32:27 PM GMT -06:00 US/Canada Central Subject: Re: [Python-ideas] python-like garbage collector & workaround castironpi-ng@comcast.net wrote:
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 destruction.
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. -- Greg ==================================== Nice response time.
Deferring the calling of the destructors doesn't help with that.
I 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. '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
I 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?