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

谁能给我解释一下:

  1. 为什么d.value的引用计数是0,如果d.value的引用计数确实是0,为什么是[=13] =] Python 没有收集垃圾?

  2. 引用对象 d 的列表究竟是什么?

谢谢!

  1. 引用计数是不是0。在CPython中你无法观察到引用计数为0的对象;您需要一个对象的引用才能对其执行任何操作,并且该引用将计入其引用计数。您看到的是该对象没有 GC 跟踪的引荐来源网址。如果你想要实际的引用计数,使用 sys.getrefcount.
  2. 没有引用该对象的列表。您正在使用 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 跟踪(或者在某些情况下,当字典被创建为跟踪字典的副本时)。