Python 对象字段的引用计数
Python reference count to object field
以下代码是 运行 在 Python3 的 Mac 终端上:
import gc
import numpy as np
class D(object):
def __init__(self):
self.value = np.arange(3)
def get(self):
return self.value
d = D()
print(gc.get_referrers(d))
print(type(gc.get_referrers(d)))
print()
print(len(gc.get_referrers(d)))
print(len(gc.get_referrers(d.value)))
print()
l = []
l.append(d)
print(len(gc.get_referrers(d)))
print(len(gc.get_referrers(d.value)))
print()
x = d.value
print(len(gc.get_referrers(d)))
print(len(gc.get_referrers(d.value)))
以上代码将return:
[{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x10de6cef0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'test3.py', '__cached__': None, 'gc': <module 'gc' (built-in)>, 'np': <module 'numpy' from '/Users/jkim/Codes/Codes/Notebooks/venv3/lib/python3.6/site-packages/numpy/__init__.py'>, 'D': <class '__main__.D'>, 'd': <__main__.D object at 0x10dec7fd0>}]
<class 'list'>
1
0
2
0
2
1
谁能给我解释一下:
为什么d.value
的引用计数是0
,如果d.value
的引用计数确实是0
,为什么是[=13] =] Python 没有收集垃圾?
引用对象 d
的列表究竟是什么?
谢谢!
- 引用计数是不是0。在CPython中你无法观察到引用计数为0的对象;您需要一个对象的引用才能对其执行任何操作,并且该引用将计入其引用计数。您看到的是该对象没有 GC 跟踪的引荐来源网址。如果你想要实际的引用计数,使用
sys.getrefcount
.
- 没有引用该对象的列表。您正在使用
gc.get_referrers
返回的引荐来源列表的类型。此列表本身不是对象的引荐来源网址。
d.value
没有 GC 跟踪的引荐来源网址,原因如下。首先,d.value
是一个 NumPy 数组,其 dtype 不能保存对象引用,因此它不能参与引用循环。 NumPy 实现通过使它们不受 GC 跟踪来优化此类数组。
其次,对 d.value
的唯一引用是 d.__dict__
中的一个引用,以及访问 d.value
或将其传递给 gc.get_referrers
时创建的临时引用。临时引用存在于当前栈帧的字节码操作数栈中,或者存在于 C 局部变量中,这些位置对 GC 不可见。 d.__dict__
只持有不能被 GC 跟踪的对象(数组和 'value'
字符串),并且 CPython dict 实现不会 GC 跟踪字典,直到插入一个键或值能够被 GC 跟踪(或者在某些情况下,当字典被创建为跟踪字典的副本时)。
以下代码是 运行 在 Python3 的 Mac 终端上:
import gc
import numpy as np
class D(object):
def __init__(self):
self.value = np.arange(3)
def get(self):
return self.value
d = D()
print(gc.get_referrers(d))
print(type(gc.get_referrers(d)))
print()
print(len(gc.get_referrers(d)))
print(len(gc.get_referrers(d.value)))
print()
l = []
l.append(d)
print(len(gc.get_referrers(d)))
print(len(gc.get_referrers(d.value)))
print()
x = d.value
print(len(gc.get_referrers(d)))
print(len(gc.get_referrers(d.value)))
以上代码将return:
[{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x10de6cef0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'test3.py', '__cached__': None, 'gc': <module 'gc' (built-in)>, 'np': <module 'numpy' from '/Users/jkim/Codes/Codes/Notebooks/venv3/lib/python3.6/site-packages/numpy/__init__.py'>, 'D': <class '__main__.D'>, 'd': <__main__.D object at 0x10dec7fd0>}]
<class 'list'>
1
0
2
0
2
1
谁能给我解释一下:
为什么
d.value
的引用计数是0
,如果d.value
的引用计数确实是0
,为什么是[=13] =] Python 没有收集垃圾?引用对象
d
的列表究竟是什么?
谢谢!
- 引用计数是不是0。在CPython中你无法观察到引用计数为0的对象;您需要一个对象的引用才能对其执行任何操作,并且该引用将计入其引用计数。您看到的是该对象没有 GC 跟踪的引荐来源网址。如果你想要实际的引用计数,使用
sys.getrefcount
. - 没有引用该对象的列表。您正在使用
gc.get_referrers
返回的引荐来源列表的类型。此列表本身不是对象的引荐来源网址。
d.value
没有 GC 跟踪的引荐来源网址,原因如下。首先,d.value
是一个 NumPy 数组,其 dtype 不能保存对象引用,因此它不能参与引用循环。 NumPy 实现通过使它们不受 GC 跟踪来优化此类数组。
其次,对 d.value
的唯一引用是 d.__dict__
中的一个引用,以及访问 d.value
或将其传递给 gc.get_referrers
时创建的临时引用。临时引用存在于当前栈帧的字节码操作数栈中,或者存在于 C 局部变量中,这些位置对 GC 不可见。 d.__dict__
只持有不能被 GC 跟踪的对象(数组和 'value'
字符串),并且 CPython dict 实现不会 GC 跟踪字典,直到插入一个键或值能够被 GC 跟踪(或者在某些情况下,当字典被创建为跟踪字典的副本时)。