Чтобы немного расширить ответ Фредерика, , раздел "подсчет ссылок" в документах хорошо объясняет обнаружение дополнительного цикла.
Поскольку я нахожу, что объяснение является хорошим способом подтверждения, я понимаю, вот несколько примеров ... С этими двумя классами:
class WithDel(object):
def __del__(self):
print "deleting %s object at %s" % (self.__class__.__name__, id(self))
class NoDel(object):
pass
Создание объекта и потеря ссылки из a
запускает метод __del__
, благодаря подсчету ссылок:
>>> a = WithDel()
>>> a = None # leaving the WithDel object with no references
deleting WithDel object at 4299615184
Если мы создадим эталонный цикл между двумя объектами без метода __del__
, все будет без утечек, на этот раз благодаря обнаружению цикла. Сначала включите вывод отладочной информации сборки мусора:
>>> import gc
>>> gc.set_debug(gc.DEBUG_COLLECTABLE | gc.DEBUG_UNCOLLECTABLE | gc.DEBUG_OBJECTS)
Затем создайте цикл ссылок между двумя объектами:
>>> a = NoDel(); b = NoDel()
>>> a.other = b; b.other = a # cyclical reference
>>> a = None; b = None # Leave only the reference-cycle
>>> gc.collect()
gc: collectable <NoDel 0x10046ed50>
gc: collectable <NoDel 0x10046ed90>
gc: collectable <dict 0x100376c20>
gc: collectable <dict 0x100376b00>
4
>>> gc.garbage
[]
(dict
от внутренних объектов __dict__
)
Все в порядке, до , даже если один из объектов в цикле содержит __del__
метод:
>>> a = NoDel(); b = WithDel()
>>> a.other = b; b.other = a
>>> a = None; b = None
>>> gc.collect()
gc: uncollectable <WithDel 0x10046edd0>
gc: uncollectable <dict 0x100376b00>
gc: uncollectable <NoDel 0x10046ed90>
gc: uncollectable <dict 0x100376c20>
4
>>> gc.garbage
[<__main__.WithDel object at 0x10046edd0>]
Как упоминал Павел, цикл можно разорвать с помощью weakref
:
>>> import weakref
>>> a = NoDel(); b = WithDel()
>>> a.other = weakref.ref(b)
>>> b.other = a # could also be a weakref
Затем, когда ссылка b
на объект WithDel
потеряна, он удаляется, несмотря на цикл:
>>> b = None
deleting WithDel object at 4299656848
>>> a.other
<weakref at 0x10045b9f0; dead>
О, объект мог бы указать на проблемный __del__
метод, подобный этому