每个 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)
…您应该能够判断(虽然不是完全可靠,但足以用于学习和测试目的)您的节点全部消失了。
如果你的节点怎么办do have __del__
方法?那么你就必须给GC一些帮助。你需要做的是打破任何包含对象的循环__del__
方法。如果列表之间没有任何节点共享,最明显的方法就是遍历列表并del
向前和向后指针。 (从技术上讲,你只需要del
两者之一,但您也可以两者都做。)如果您需要__del__
节点上的方法,您可能需要顶层的方法dl_list
(or tree_node
或者任何拥有这些的东西),所以这是一个明显的放置它的地方。
当然如果你不需要__del__
方法,还有一个更简单的解决方案:摆脱它。
最后一种可能性是使用weakref用于反向链接,但常规引用用于正向链接。这样,就不存在可能的循环。但是您在添加和删除节点时必须小心一些,以确保您不会暂时留下一个除了弱引用之外什么都没有的节点。
如果您使用 Jython 或 IronPython,则垃圾收集与底层运行时(JVM 或 .NET)相关联,因此您必须阅读相应的文档。
PyPy 有自己的垃圾收集器(实际上是不同选项的选择),您可以阅读here.
如果您使用的是不太常见的实现,应该有类似的文档可用。