我应该担心Python中的循环引用吗?

时间:2010-03-11 20:11:29

标签: python

假设我有维护父/子结构的代码。在这样的结构中,我得到循环引用,其中孩子指向父母,父母指向孩子。我应该担心吗?我正在使用Python 2.5。

我担心它们不会被垃圾收集,应用程序最终会占用所有内存。

6 个答案:

答案 0 :(得分:32)

“忧虑”是错误的,但是如果你的程序结果很慢,消耗的内存比预期的要多,或者有一些奇怪的莫名其妙的停顿,原因确实可能是那些垃圾引用循环 - 它们需要是垃圾通过与“普通”(非循环)参考图表不同的过程收集,并且该集合是偶然的,如果您在这样的循环中绑定了大量对象,则可能会很慢(如果某个对象在循环中,则循环垃圾收集也会被禁止) loop有一个__del__特殊方法。)

因此,引用循环不会影响程序的正确性,但可能会影响其性能和/或占用空间。

如果您想删除不需要的引用循环,通常可以在Python的标准库中使用weakref模块。

如果您想要进行更多关于循环垃圾收集的直接控制(或执行调试,看看究竟发生了什么),请使用Python标准库中的gc模块。

答案 1 :(得分:18)

实验:你很好:

import itertools

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

它一直使用3.6 MB的RAM。

答案 2 :(得分:11)

当没有外部引用时,Python将检测周期并释放内存。

答案 3 :(得分:7)

循环引用是正常的事情,所以我没有理由担心它们。许多树算法要求每个节点都有到其子节点及其父节点的链接。他们还需要实现类似双重链接的列表。

答案 4 :(得分:3)

我认为你不应该担心。尝试以下程序,你会发现它不会占用所有内存:

while True:
    a=range(100)
    b=range(100)
    a.append(b)
    b.append(a)
    a.append(a)
    b.append(b)

答案 5 :(得分:2)

对变量列表中的方法的引用似乎存在问题。这是两个例子。第一个不会调用__del__。对于__del__,第二个with weakref是可以的。但是,在后一种情况下,问题是您不能弱引用方法: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)