Fre*_*rik 6 python garbage-collection cpython
我试图了解CPython垃圾收集器的内部结构,特别是在调用析构函数时.到目前为止,行为是直观的,但以下情况让我感到震惊:
我以为只有启用垃圾收集器才会发生这种情况.有人可以解释为什么会这样吗?有没有办法推迟调用析构函数?
import gc
import unittest
_destroyed = False
class MyClass(object):
def __del__(self):
global _destroyed
_destroyed = True
class GarbageCollectionTest(unittest.TestCase):
def testExplicitGarbageCollection(self):
gc.disable()
ref = MyClass()
ref = None
# The next test fails.
# The object is automatically destroyed even with the collector turned off.
self.assertFalse(_destroyed)
gc.collect()
self.assertTrue(_destroyed)
if __name__=='__main__':
unittest.main()
Run Code Online (Sandbox Code Playgroud)
免责声明:此代码不适用于生产 - 我已经注意到这是特定于实现的,并且不适用于Jython.
Python有引用计数垃圾收集和循环垃圾收集,它是gc模块控制的后者.无法禁用引用计数,因此在循环垃圾收集器关闭时仍会发生.
由于之后没有任何引用留给你的对象ref = None,__del__因此它的引用计数为零时调用它的方法.
文档中有一条线索:"由于收集器补充了Python中已经使用的引用计数......"(我的重点).
您可以通过使对象引用自身来停止第一个断言,因此它的引用计数不会变为零,例如通过给它构造函数:
def __init__(self):
self.myself = self
Run Code Online (Sandbox Code Playgroud)
但如果你这样做,第二个断言将会触发.那是因为__del__没有收集带方法的垃圾循环- 请参阅gc.garbage的文档.
这里的文档(原始链接是一个文档部分,直到 Python 3.5 在这里,后来被重新定位)解释了所谓的“可选垃圾收集器”实际上是一个循环垃圾收集器(引用计数不会捕获)(另请参见此处)。这里解释了引用计数,并提到了它与循环的相互作用gc:
虽然 Python 使用传统的引用计数实现,但它还提供了一个循环检测器来检测引用循环。这让应用程序不必担心创建直接或间接的循环引用;这些是仅使用引用计数实现的垃圾收集的弱点。引用循环由包含(可能是间接的)对自身的引用的对象组成,因此循环中的每个对象都有一个非零的引用计数。典型的引用计数实现无法回收属于引用循环中任何对象的内存,或从循环中的对象引用的内存,即使没有对循环本身的进一步引用。
| 归档时间: |
|
| 查看次数: |
424 次 |
| 最近记录: |