Стоит ли беспокоиться о циклических ссылках в Python? - PullRequest
39 голосов
/ 11 марта 2010

Предположим, у меня есть код, который поддерживает структуру parent / children. В такой структуре я получаю циклические ссылки, где ребенок указывает на родителя, а родитель указывает на ребенка. Должен ли я беспокоиться о них? Я использую Python 2.5.

Я обеспокоен тем, что они не будут собирать мусор, и приложение в конечном итоге будет использовать всю память.

Ответы [ 6 ]

32 голосов
/ 12 марта 2010

«Беспокойство» неуместно, но если ваша программа работает медленно, потребляет больше памяти, чем ожидалось, или имеет странные необъяснимые паузы, причина, вероятно, кроется в этих ссылочных циклах мусора - они должны быть мусором собирается другой процедурой, чем «нормальные» (ациклические) ссылочные графы, и эта коллекция является случайной и может быть медленной, если в такие циклы связано много объектов (сбор циклического мусора также запрещается, если объект в цикл имеет __del__ специальный метод).

Таким образом, циклы ссылок не влияют на правильность вашей программы, но могут повлиять на ее производительность и / или занимаемую площадь.

Если и когда вы хотите удалить нежелательные циклы ссылок, вы часто можете использовать модуль weakref в стандартной библиотеке Python.

Если и когда вы хотите обеспечить более прямой контроль (или выполнить отладку, посмотреть, что именно происходит) относительно циклического сбора мусора, используйте модуль gc в стандартной библиотеке Python.

18 голосов
/ 11 марта 2010

Экспериментально: ты в порядке:

import itertools

for i in itertools.count():
    a = {}
    b = {"a":a}
    a["b"] = b

Постоянно используется 3,6 МБ ОЗУ.

11 голосов
/ 11 марта 2010

Python обнаружит цикл и освободит память при отсутствии внешних ссылок.

7 голосов
/ 11 марта 2010

Циркулярные ссылки - это нормальное занятие, поэтому я не вижу причин беспокоиться о них. Многие алгоритмы дерева требуют, чтобы каждый узел имел ссылки на своих дочерних и родительских элементов. Они также должны реализовывать что-то вроде двусвязного списка.

3 голосов
/ 11 марта 2010

Не думаю, что тебе стоит волноваться. Попробуйте следующую программу, и вы увидите, что она не будет использовать всю память:

while True:
    a=range(100)
    b=range(100)
    a.append(b)
    b.append(a)
    a.append(a)
    b.append(b)
2 голосов
/ 22 ноября 2012

Кажется, есть проблема со ссылками на методы в списках в переменной. Вот два примера. Первый не вызывает __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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...