[Python-Dev] Garbage collector problem

Tim Peters tim.one@comcast.net
Fri, 28 Jun 2002 18:58:30 -0400

> ...
> I'm not yet sure whether the mystery is why this happens in 2.3, or
> why it doesn't happen in 2.2.1 <0.5 wink>.

Knock that down to 0.1 wink <0.3 wink>:  Kevin's problem goes away in
current CVS if I change the guard in visit_decref() to

		if (IS_TRACKED(op) && !IS_MOVED(op))
                               ^^^^^^^^^^^^^^^^  added this

I've no real idea why, as 2.2.1 didn't need this to prevent "the list" from
getting continually pulled back into a younger generation.

Without this change in current CVS, it looks like, in each gen0 collection:

a. The bound method object in gen0 knocks "the list"'s gc_refs down to
   -124 when visit_decref() is called by the bound method object
   traverse via subtract_refs().  Therefore IS_MOVED("the list") is
   no longer true.

b. move_root_reachable() then moves "the list" into the list of
   reachable things, because visit_move's has-always-been-there

		if (IS_TRACKED(op) && !IS_MOVED(op)) {

   guard doesn't believe "the list" has already been moved.  vist_move
   then restores the list's gc_refs to the magic -123.

c. move_root_reachable() goes on to scan all of "the list"'s entries too.

d. "the list" itself gets moved into gen1, just because it's in the
   list of reachable things.

e. The next gen0 collection starts at #a again, and does the same
   stuff all over again.

Adding the new guard in visit_decref() breaks this at #a:  IS_MOVED("the
list") remains true, and so #b doesn't move "the list" into the set of
reachable objects again, and so the list stays in whichever older generation
it was in, and doesn't get scanned again (until the next gen2 traversal).

The mystery to me now is why the a,b,c,d,e loop didn't happen in 2.2.1.