The following code is run on Mac terminal on Python3:
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)))
The above code will 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
Could anyone explain to me:
Why is reference count to
d.value0, and if the reference count tod.valueis indeed0, why isd.valuenot getting garbage collected by Python?What exactly is the list that the object
dis being referred by?
Thank you!
1 Answer 1
- The reference count is not 0. You cannot observe an object with a 0 reference count in CPython; you need a reference to an object to do anything with it, and that reference will count toward its reference count. What you're seeing is that there are no GC-tracked referrers for the object. If you want the actual reference count, use
sys.getrefcount. - There is no list with a reference to the object. You're taking the type of the list of referrers returned by
gc.get_referrers. This list is not itself a referrer of the object.
d.value has no GC-tracked referrers for the following reason. First, d.value is a NumPy array with a dtype that cannot hold object references, so it cannot participate in a reference cycle. The NumPy implementation optimizes such arrays by making them GC-untracked.
Second, the only references to d.value are one reference in d.__dict__, and the temporary references created when you access d.value or pass it to gc.get_referrers. The temporary references live in the current stack frame's bytecode operand stack, or in C local variables, and those locations aren't visible to the GC. d.__dict__ has only ever held objects that cannot be GC-tracked (the array and the 'value' string), and the CPython dict implementation does not GC-track a dict until a key or value is inserted that is capable of being GC-tracked (or in some cases when a dict is created as a copy of a tracked dict).
object? Is this Python 2? If so, please tag it as such.