我们可以删除引用循环对象并释放它的内存吗?

Can we delete reference cycle object and free its memory?

我阅读了有关垃圾回收的不同文章。他们说我们需要 gc 模块来清理引用循环对象。但是我们可以通过简单地使用 del 来进行清理吗?

例如,如果我执行以下操作,我是否成功释放了这个引用循环对象的内存?如果是,那我们为什么还需要 gc 模块呢?如果不是,那为什么不呢?

>>> x = [1, 2, 3]    
>>> x.append(x)    # create reference cycle
>>> print(x)
[1, 2, 3, [...]]
>>> sys.getrefcount(x)
3


>>> del x[3]
>>> print(x)
[1, 2, 3]
>>> sys.getrefcount(x)
2
>>> del x    # reference count of x goes to 0!

cpython 是引用计数的。当对象引用计数变为零时,它将被删除——这是与导致减少的代码内联完成的。垃圾收集器在那里处理对象无法访问但其引用计数不为零的情况。并不是说每个循环引用都需要垃圾回收。引用的展开方式很重要。

>>> x = [1, 2, 3] 

我们创建了一个列表并将其绑定到 x。该列表本身只是内存中的一个匿名对象,但目前可以通过 x 访问。让我们调用实际对象 列表 .

>>> x.append(x)    # create reference cycle
>>> print(x)
[1, 2, 3, [...]]
>>> sys.getrefcount(x)
3

此时,列表 引用了 x、它自己的第 4 个元素和 getrefcount 参数(当函数 returns, 留下 2 个参考文献).

>>> del x[3]

del 实际上并没有删除东西。它解除绑定对象。在这种情况下,列表的 __delitem__ 函数被称为解除绑定 列表 从它自己的第 4 个元素,留下一个引用。

>>> del x

这次 delx 中解除 列表 的绑定,并从命名空间中删除 x。引用计数变为零,列表 被删除。从未涉及垃圾收集器。

现在让我们混合起来。

>>> x = [1, 2, 3]    
>>> x.append(x)    # create reference cycle

我们有 2 个引用列表。不过这次只是

>>> del x

delx 解除绑定 列表 并将其引用计数减至 1。这不足以删除 列表 。现在我们有一个问题。 列表不再分配给我们可以访问的任何变量。它不在 x 中,因为 x 不再存在。但它仍然在记忆中。这就是垃圾收集器试图解决的问题。

我们不能只使用 del,因为没有变量可以执行 del