Должен ли я беспокоиться о круговых ссылках на Python?
Предположим, что у меня есть код, который поддерживает структуру родителя/ребенка. В такой структуре я получаю круговые ссылки, где ребенок указывает на родителя, а родитель указывает на ребенка. Должен ли я беспокоиться о них? Я использую Python 2.5.
Я обеспокоен тем, что они не будут собирать мусор, и приложение в конечном итоге уничтожит всю память.
Ответы
Ответ 1
"Беспокойство" неуместно, но если ваша программа оказывается медленной, потребляет больше памяти, чем ожидалось, или имеет странные необъяснимые паузы, причина, скорее всего, будет в этих циклах обработки мусора - им нужно быть мусором собранных по другой процедуре, чем "нормальные" (ациклические) эталонные графы, и эта коллекция является случайной и может быть медленной, если у вас много объектов, связанных в таких циклах (коллекция циклических мусора также запрещена, если объект в цикл имеет специальный метод __del__
).
Таким образом, циклы ссылок не повлияют на правильность вашей программы, но могут повлиять на ее производительность и/или площадь.
Если и когда вы хотите удалить ненужные циклы ссылок, вы можете часто использовать модуль weakref в стандартной библиотеке Python.
Если и когда вы хотите использовать более прямой контроль (или выполнить отладку, посмотрите, что именно происходит) в отношении циклической сборки мусора, используйте gc в стандартной библиотеке Python.
Ответ 2
Экспериментально: вы в порядке:
import itertools
for i in itertools.count():
a = {}
b = {"a":a}
a["b"] = b
Он постоянно остается при использовании 3,6 Мб ОЗУ.
Ответ 3
Python обнаружит цикл и освободит память, если нет внешних ссылок.
Ответ 4
Циркулярные ссылки - это нормальная вещь, поэтому я не вижу причины беспокоиться о них. Многие алгоритмы дерева требуют, чтобы каждый node имел ссылки на своих дочерних элементов и родителя. Они также должны реализовать что-то вроде двусвязного списка.
Ответ 5
Я не думаю, что тебе следует беспокоиться. Попробуйте следующую программу, и вы увидите, что она не будет потреблять всю память:
while True:
a=range(100)
b=range(100)
a.append(b)
b.append(a)
a.append(a)
b.append(b)
Ответ 6
Кажется, что существует проблема со ссылками на методы в списках в переменной. Вот два примера. Первый не вызывает __del__
. Второй со слабым реком подходит для __del__
. Однако в этом более позднем случае проблема заключается в том, что вы не можете слабо ссылаться на методы: http://docs.python.org/2/library/weakref.html
import sys, weakref
class One():
def __init__(self):
self.counters = [ self.count ]
def __del__(self):
print("__del__ called")
def count(self):
print(sys.getrefcount(self))
sys.getrefcount(One)
one = One()
sys.getrefcount(One)
del one
sys.getrefcount(One)
class Two():
def __init__(self):
self.counters = [ weakref.ref(self.count) ]
def __del__(self):
print("__del__ called")
def count(self):
print(sys.getrefcount(self))
sys.getrefcount(Two)
two = Two()
sys.getrefcount(Two)
del two
sys.getrefcount(Two)