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_ref
和 bar_ref
分别保留对foo
和bar
的弱引用,只要它们相互引用*,但这反而打印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__()
方法,我们防止了引用循环被垃圾回收,但任何孤立的对象都将被删除。
请注意,为了使其正常工作,您需要循环引用;无论如何,对象图中不属于引用圆的任何对象都将被拾取。