[Python-Dev] Bizarre new test failure
Tim Peters
tim.one@comcast.net
Fri, 07 Jun 2002 13:51:16 -0400
[Jeremy Hylton, explains the cells in Neil's example]
Thanks! That was helpful.
> ...
> class A refers to
> function __init__ refers to
> cell for A refers to
> class A
>
> That's it for what I understand.
Where does the singleton tuple containing a cell come from? I guess it must
be in function __init__.
> It looks like the example code creates two cycles, and one cycle
> refers to the other. The first cycle is the one involving the A
> instance and the super instance variable. That cycle has a reference
> to class A.
>
> When the garbage collector runs, it determines the first cycle is
> garbage. It doesn't determine the second cycle is garbage because it
> has an external reference from the first cycle.
The proper understanding of "external" here is wrt all the objects GC
tracks. So long as references are *within* that grand set, there are no
external references in a relevant sense. "External" means stuff like the
reference is due to an untracked container, or to a C variable -- stuff like
that.
> I presume that the garbage collector can't collect both cycles in one
> pass without re-running the update & subtract refs phase after
> deleting all the garbage. During the first refs pass, the second
> cycle wasn't detected. The second cycle is only collectable after the
> first cycle has been collected.
I don't think that's it. Here:
C:\Code\python\PCbuild>python
Python 2.3a0 (#29, Jun 5 2002, 23:17:02) [MSC 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> class A: pass
...
>>> class B: pass
...
>>> A.a = A # one cycle
>>> B.b = B # another
>>> A.b = B # point the first cycle at the second
>>> import gc
>>> gc.collect()
0
>>> gc.set_debug(gc.DEBUG_SAVEALL)
>>> del B
>>> gc.collect() # A still keeping everything alive
0
>>> del A # Both cycles are trash now
>>> gc.collect() # And both are recoved in one pass
4
>>> print gc.garbage
[<class __main__.A at 0x0065D120>,
{'a': <class __main__.A at 0x0065D120>,
'__module__': '__main__',
'b': <class __main__.B at 0x0065D1B0>,
'__doc__': None
},
<class __main__.B at 0x0065D1B0>,
{'__module__': '__main__',
'b': <class __main__.B at 0x0065D1B0>,
'__doc__': None
}
]
>>>