0
votes

During development of a project I've been working on I've been working on I've encountered a problem with garbage collector not able to de-allocate linked lists or even lists.

class B(object):
    def __init__(self, previous):
        self.previous = previous
    def __del__(self):
        self.previous = None
        self = None
import gc
gc.set_debug(gc.DEBUG_LEAK)
l = []
prev = None
for i in range(1000000):
    b = B(prev)
    l.append(b)
    prev = b

del l[:]
gc.collect()
print gc.garbage

When I check the memory usage before allocation and after allocation and after deletion. Memory usage after allocation is still the same as the Memory usage after deletion. and the garbage collector doesn't complain about any memory leaks.

When I use pympler to track objects in the python environment. the objects don't exist yet there's memory allocated for them.

However, This issue only arises when instances are linked. If an instances don't have a reference to each others. Garbage collector behaves normally.

Any idea why?

1
In the above code, after del l[:] your full list is still accessible via the b and prev references. - sebastian

1 Answers

2
votes

You may have cleared out l, but b and prev still reference the last B instance created. In turn, that instance refers to the previous instance created, etc. keeping the whole chain alive:

>>> class B(object):
...     def __init__(self, previous):
...         self.previous = previous
...     def __del__(self):
...         self.previous = None
...         self = None
... 
>>> l = []
>>> prev = None
>>> for i in range(1000000):
...     b = B(prev)
...     l.append(b)
...     prev = b
... 
>>> del l[:]
>>> prev
<__main__.B object at 0x11f269d50>
>>> b
<__main__.B object at 0x11f269d50>
>>> b.previous
<__main__.B object at 0x11f269d10>
>>> import gc
>>> sum(1 for ob in gc.get_objects() if isinstance(ob, B))
1000000
>>> del b, prev
>>> sum(1 for ob in gc.get_objects() if isinstance(ob, B))
0

The gc.garbage list would only ever list B instances if there is a circular reference; e.g. if the last B instance in the chain referenced another instance in the same chain, and not None.