2024-05-13 10:37:14 发布
网友
使用objgraph,我发现了一堆这样的对象:
Python的垃圾收集器会处理这样的循环,还是会泄漏?
环的视野稍宽:
为了对Frédéric的答案进行一些扩展,文档中的the "reference counts" section很好地解释了补充循环检测。
既然我觉得解释是确认我理解的好方法,这里有一些例子。。。对于这两个类:
class WithDel(object): def __del__(self): print "deleting %s object at %s" % (self.__class__.__name__, id(self)) class NoDel(object): pass
创建对象并丢失来自a的引用将触发__del__方法,这要归功于ref计数:
a
__del__
>>> a = WithDel() >>> a = None # leaving the WithDel object with no references deleting WithDel object at 4299615184
如果我们用no__del__方法在两个对象之间建立一个引用循环,那么这次由于循环检测,所有对象仍然是无泄漏的。首先,启用垃圾回收调试输出:
>>> import gc >>> gc.set_debug(gc.DEBUG_COLLECTABLE | gc.DEBUG_UNCOLLECTABLE | gc.DEBUG_OBJECTS)
然后在两个对象之间创建一个引用循环:
>>> a = NoDel(); b = NoDel() >>> a.other = b; b.other = a # cyclical reference >>> a = None; b = None # Leave only the reference-cycle >>> gc.collect() gc: collectable <NoDel 0x10046ed50> gc: collectable <NoDel 0x10046ed90> gc: collectable <dict 0x100376c20> gc: collectable <dict 0x100376b00> 4 >>> gc.garbage []
(该dict来自对象的内部__dict__属性)
dict
__dict__
一切都很好,直到甚至循环中的一个对象包含一个__del__方法:
>>> a = NoDel(); b = WithDel() >>> a.other = b; b.other = a >>> a = None; b = None >>> gc.collect() gc: uncollectable <WithDel 0x10046edd0> gc: uncollectable <dict 0x100376b00> gc: uncollectable <NoDel 0x10046ed90> gc: uncollectable <dict 0x100376c20> 4 >>> gc.garbage [<__main__.WithDel object at 0x10046edd0>]
正如Paul提到的,循环可以用^{}来中断:
>>> import weakref >>> a = NoDel(); b = WithDel() >>> a.other = weakref.ref(b) >>> b.other = a # could also be a weakref
然后,当对WithDel对象的b引用丢失时,它将被删除,尽管周期是:
WithDel
b
>>> b = None deleting WithDel object at 4299656848 >>> a.other <weakref at 0x10045b9f0; dead>
哦,objgraph会有帮助的indicated the problematic ^{} method like this
Python的标准引用计数机制无法释放周期,因此示例中的结构将泄漏。
但是,supplemental garbage collection facility在默认情况下是启用的,如果它的任何组件都不能从外部访问,并且它们没有__del__()方法,则应该能够释放该结构。
__del__()
如果是,垃圾收集器will not free them因为它无法确定运行这些__del__()方法的安全顺序。
Python的GC被设计为遍历所有活动对象,以便在没有外部引用的情况下定位和消除引用周期。
您可以通过运行gc.collect(),然后打印gc.garbage和gc.get_objects来验证正在发生的情况。
gc.collect()
gc.garbage
为了对Frédéric的答案进行一些扩展,文档中的the "reference counts" section很好地解释了补充循环检测。
既然我觉得解释是确认我理解的好方法,这里有一些例子。。。对于这两个类:
创建对象并丢失来自
a
的引用将触发__del__
方法,这要归功于ref计数:如果我们用no
__del__
方法在两个对象之间建立一个引用循环,那么这次由于循环检测,所有对象仍然是无泄漏的。首先,启用垃圾回收调试输出:然后在两个对象之间创建一个引用循环:
(该
dict
来自对象的内部__dict__
属性)一切都很好,直到甚至循环中的一个对象包含一个
__del__
方法:正如Paul提到的,循环可以用^{} 来中断:
然后,当对
WithDel
对象的b
引用丢失时,它将被删除,尽管周期是:哦,objgraph会有帮助的indicated the problematic ^{} method like this
Python的标准引用计数机制无法释放周期,因此示例中的结构将泄漏。
但是,supplemental garbage collection facility在默认情况下是启用的,如果它的任何组件都不能从外部访问,并且它们没有
__del__()
方法,则应该能够释放该结构。如果是,垃圾收集器will not free them因为它无法确定运行这些
__del__()
方法的安全顺序。Python的GC被设计为遍历所有活动对象,以便在没有外部引用的情况下定位和消除引用周期。
您可以通过运行
gc.collect()
,然后打印gc.garbage
和gc.get_objects来验证正在发生的情况。相关问题 更多 >
编程相关推荐