每个 Python 实现都有不同的垃圾收集方案。通用答案是“是的,如果是垃圾,就应该进行垃圾收集”。但是您可能想要比这更具体的东西。
在 CPython 中,垃圾收集使用引用计数和循环收集器。如果一个对象的引用计数下降到 0,它就会被清除。但是在您的情况下,当对您的列表的所有外部引用都消失时,仍然会有内部引用,因此引用计数本身无法解决您的问题。这就是循环收集器的用途。
假设您的节点没有__del__
方法,并且您没有(直接或间接)禁用“补充垃圾收集”(默认情况下启用),循环收集器将检测到您的节点都相互引用,但没有其他引用它们, 并将其清理干净。(这可能需要两次,因为它使用了代系统。)
您可以使用该gc
模块显式运行循环收集器 ( gc.collect()
) 而不是等待它,或者检查它在做什么。例如,如果您这样做:
gc.collect()
oldcounts = gc.get_counts()
del last_reference_to_list
gc.collect()
newcounts = gc.get_counts()
print(oldcounts, newcounts)
......你应该能够告诉(不是完全可靠,但足以用于学习和测试目的)你的节点都已经消失了。
如果您的节点确实有__del__
方法怎么办?然后你将不得不给 GC 一些帮助。您需要做的是打破包含带有__del__
方法的对象的任何循环。如果列表之间没有任何节点共享,那么明显的方法就是遍历列表以及del
前向和后向指针。(从技术上讲,你只需要del
一个或另一个,但你也可以两者都做。)如果你需要__del__
节点上的方法,你可能需要顶层的方法dl_list
(或tree_node
拥有这些的任何东西),所以这是一个很明显的地方。
当然,如果您不需要该__del__
方法,还有一个更简单的解决方案:摆脱它。
最后一种可能性是weakref
用于反向链接,但常规引用用于正向链接。这样,就没有可能的循环。但是你必须小心地添加和删除节点,以确保你永远不会暂时离开一个节点,除了一个弱引用之外什么都没有。
如果您使用的是 Jython 或 IronPython,垃圾收集与底层运行时(JVM 或 .NET)相关联,因此您必须阅读相应的文档。
PyPy 有自己的垃圾收集器(实际上,可以选择不同的选项),您可以在此处阅读。
如果您使用的是不太常见的实现,则应该有类似的文档可用。