垃圾收集后保留循环引用

时间:2012-08-19 11:16:01

标签: python garbage-collection weak-references circular-reference

import weakref
import gc

class MyClass(object):
    def refer_to(self, thing):
        self.refers_to = thing

foo = MyClass()
bar = MyClass()
foo.refer_to(bar)
bar.refer_to(foo)
foo_ref = weakref.ref(foo)
bar_ref = weakref.ref(bar)
del foo
del bar
gc.collect()
print foo_ref()

我希望foo_refbar_ref分别保留对foobar的弱引用,只要它们互相引用 * ,但而是打印None。如何防止垃圾收集器在引用周期内收集某些对象?

bar应该在此代码中进行垃圾回收,因为它不再是foo - bar引用周期的一部分:

baz = MyClass()
baz.refer_to(foo)
foo.refer_to(baz)
gc.collect()

* 我意识到防止循环引用被垃圾收集似乎毫无意义,但我的用例需要它。我有一堆对象以类似Web的方式相互引用,还有一个WeakValueDictionary,它对一堆中的每个对象保持弱引用。我只希望群中的一个对象在孤立时被垃圾收集,即当群中没有其他对象引用它时。

1 个答案:

答案 0 :(得分:2)

通常使用弱引用意味着您无法阻止对象被垃圾回收。

但是,您可以使用一种技巧来防止对象部分参考周期被垃圾回收:在这些上定义__del__() method

来自gc module documentation

  

<强> gc.garbage

     

收集器发现无法访问但无法释放的对象列表(无法收集的对象)。默认情况下,此列表   仅包含具有__del__()方法的对象。有的对象   __del__()方法是参考周期的一部分,导致整个参考周期无法收集,包括对象不一定   在循环中但只能从它到达。 Python不收集这样的   自动循环,因为一般来说,Python不可能   猜测运行__del__()方法的安全顺序。如果你   知道一个安全的命令,你可以通过检查垃圾来强制解决问题   列表,并明确地打破由于您的对象内的周期   名单。请注意,这些物体即使如此也能保持活力   在垃圾清单中,所以它们也应该从垃圾中删除。   例如,在打破周期后,执行del gc.garbage[:]清空   名单。通过不创建周期来避免这个问题通常会更好   包含__del__()方法的对象,可以检查垃圾   在这种情况下,要验证没有创建这样的周期。

如下所示定义MyClass

class MyClass(object):
    def refer_to(self, thing):
        self.refers_to = thing
    def __del__(self):
        print 'Being deleted now, bye-bye!'

然后您的示例脚本打印:

<__main__.MyClass object at 0x108476a50>

但评论其中一个.refer_to()来电会导致:

Being deleted now, bye-bye!
Being deleted now, bye-bye!
None

换句话说,通过简单地定义了__del__()方法,我们阻止了引用循环被垃圾收集,但任何孤立的对象都被删除。

请注意,为了使其正常工作,您需要循环引用;无论如何,对象图中参考圆的一部分的任何对象都将被拾取。