举个例子:
>>> import gc
>>> d = { 1 : object() }
>>> gc.get_referrers(d[1])
[] # Python 2.7
[{1: <object object at 0x003A0468>}] # Python 2.5
为什么没有被d
列为对象的引用者?
EDIT1:虽然 d 中的 dict 引用了对象,但为什么没有列出字典?
举个例子:
>>> import gc
>>> d = { 1 : object() }
>>> gc.get_referrers(d[1])
[] # Python 2.7
[{1: <object object at 0x003A0468>}] # Python 2.5
为什么没有被d
列为对象的引用者?
EDIT1:虽然 d 中的 dict 引用了对象,但为什么没有列出字典?
该文档提到:
这个函数只会定位那些支持垃圾回收的容器;不会找到确实引用其他对象但不支持垃圾回收的扩展类型。
似乎字典不支持它。
这就是为什么:
垃圾收集器试图避免跟踪不能成为循环一部分的简单容器。在 Python 2.7 中,现在对于包含原子类型(如整数、字符串等)的元组和字典也是如此。传递地,包含原子类型元组的 dict 也不会被跟踪。这通过减少收集器要考虑和遍历的对象的数量来帮助降低每次垃圾收集的成本。
— 来自Python 2.7 的新增功能
这似乎object()
被认为是一种原子类型,并且尝试使用用户定义类的实例(即 not object
)来确认这一点,因为您的代码现在可以工作。
# Python 2.7
>>> class A(object): pass
>>> r = A()
>>> d = {1: r}
>>> del r
>>> gc.get_referrers(d[1])
[{1: <__main__.A instance at 0x0000000002663708>}]
另见问题 4688。
这是 Python 2.7 中对象跟踪方式的变化;仅包含原子类型(包括 的实例object()
)的元组和字典不再需要循环中断,不再列出。
见http://bugs.python.org/issue4688;这是为了避免在创建大量元组或字典时出现性能问题。
解决方法是在需要跟踪的字典中添加一个对象:
>>> gc.is_tracked(d)
False
>>> class Foo(object): pass
...
>>> d['_'] = Foo()
>>> gc.is_tracked(d)
True
>>> d in gc.get_referrers(r)
True
一旦被跟踪,字典只会在 gc 收集周期后恢复为未被跟踪:
>>> del d['_']
>>> gc.is_tracked(d)
True
>>> d in gc.get_referrers(r)
True
>>> gc.collect()
0
>>> gc.is_tracked(d)
False
>>> d in gc.get_referrers(r)
False