Amaury Forgeot d'Arc added the comment:

Finally I found a potential problem with the garbage collector in a
specific case:
- Some object C participates in a reference cycle, and contains a
reference to another object X.
- X.__del__ 'resurrect' the object, by saving its 'self' somewhere else.
- X contains a reference to Y, which has a __del__ method.
When collecting all this, gc.garbage == [Y] !
This is not true garbage: if you clean gc.garbage, then the next
gc.collect() clears everything.


Now, try to follow my explanation (if I correctly understand the gc
internals):
- When the cycle is garbage collected, X and Y are detected as
'unreachable with finalizers', and put in a specific 'finalizers' list.
- the cycle is broken, C is deallocated. 
- This correctly triggers X.__del__. X is removed from the 'finalizers'
list.
- when X is resurrected, it comes back to the normal gc tracking list.
- At the end, 'finalizers' contains 3 objects: X.__dict__, Y and Y.__dict__.
- Y is then considered as garbage.

I join a script which reproduces the behaviour. Note that 2.4 and 2.5
are affected too.
In py3k, the 'resurrect' seems to be caused by a (caught) exception in
TextIOWrapper.close(): the exception contains a reference to the frame,
which references the self variable.

----------
components: +Interpreter Core
nosy: +gvanrossum
Added file: http://bugs.python.org/file8880/gc_bug.py

__________________________________
Tracker <[EMAIL PROTECTED]>
<http://bugs.python.org/issue1540>
__________________________________
import gc
gc.set_debug(gc.DEBUG_UNCOLLECTABLE|gc.DEBUG_COLLECTABLE|gc.DEBUG_OBJECTS)

class Cycle:
    def __init__(self):
        self.c = self

class Immortal:
    resurrected = []
    
    def __del__(self):
        self.resurrected.append(self)

class Finalizer:
    def __del__(self):
        pass

cycle = Cycle()
cycle.x = Immortal()
cycle.x.y = Finalizer()

print (gc.collect(), gc.garbage)
assert gc.garbage == []
# Nothing special so far

del cycle

print (gc.collect(), gc.garbage)
# 'Finalizer' instance appears in garbage.
# Not real garbage though:
del gc.garbage[0]
gc.collect()
assert gc.garbage == []
_______________________________________________
Python-bugs-list mailing list 
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to