python会自动垃圾收集双链表吗?

时间:2013-08-05 21:58:42

标签: python garbage-collection doubly-linked-list

背景

我有一个树形结构。在这个树结构中,我将节点的孩子保持为双向链表:

enter image description here
(来源:Doubly linked list

(由于创建此列表的广度优先搜索方法,我选择了此结构。)

问题

现在我关心的是垃圾收集器是否可以自动销毁此列表。当然,我只保留对这三者的根节点的引用。 Afaik GC的原理是它收集内存中的数据结构,其中没有指向任何引用。但是在双向链表中,每个节点都是从它的兄弟节点引用的,兄弟节点引用节点。所以总是会引用一个节点,而GC永远不会收集它。

垃圾收集器会处理双向链表吗?

如果没有,收集它的最简单方法是什么?

相关问题:

Why does Lua use a garbage collector instead of reference counting?
Python: Memory usage and optimization when modifying lists

1 个答案:

答案 0 :(得分:9)

每个Python实现都有不同的垃圾收集方案。通用答案是“是的,如果它是垃圾,它应该是垃圾收集。”但是你可能想要比这更具体的东西。


在CPython中,垃圾收集使用引用计数和循环收集器。如果对象的引用计数降为0,则会清除它。但是在你的情况下,当你的列表的所有外部引用都消失了,仍然会有内部引用,所以refcounting本身并不能解决你的问题。这就是循环收集器的用途。

假设您的节点没有__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__方法,则可能需要在顶层{ {1}}(或dl_list或拥有这些内容的任何东西),这是一个显而易见的地方。

当然,如果你不需要tree_node方法,那么有一个更简单的解决方案:只需摆脱它。


最后一种可能性是使用weakref作为反向链接,但是使用前向链接的常规参考。这样,就没有可能的周期。但是你必须要小心添加和删除节点,以确保你永远不会暂时让一个节点只有一个弱参数。


如果您正在使用Jython或IronPython,则垃圾收集将与底层运行时(JVM或.NET)绑定,因此您必须阅读相应的文档。

PyPy有自己的垃圾收集器(实际上,可以选择不同的选项),您可以阅读here

如果您使用的是不太常见的实现,则应该提供类似的文档。