在垃圾回收后保留循环引用


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()

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

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

但是,您可以使用一个技巧来防止引用周期的对象被垃圾回收:在这些对象上定义一个__del__()方法。

gc模块文档中:

gc.垃圾

收集器

发现无法访问但无法释放的对象列表(不可收集的对象(。默认情况下,此列表 仅包含具有__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__()方法,我们防止了引用循环被垃圾回收,但任何孤立的对象都将被删除。

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

相关内容

  • 没有找到相关文章

最新更新