python会自动垃圾收集双向链表吗? [复制]

Posted

技术标签:

【中文标题】python会自动垃圾收集双向链表吗? [复制]【英文标题】:Will python automatically garbage collect doubly-linked list? [duplicate] 【发布时间】:2013-08-06 18:29:13 【问题描述】:

背景

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

(来源: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

【问题讨论】:

只要你没有引用程序中的任何节点,它应该 GC 是不可访问的......(afaik 这仅适用于 cython)我认为它只会 gc 如果你尚未实现 del 方法(请参阅其他评论的答案) 是的,最终。但是,如果您需要对垃圾收集进行真正细粒度的控制,我建议您使用低级得多的语言,或者至少使用 Python 的 gc 库。 【参考方案1】:

每个 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 有自己的垃圾收集器(实际上,有不同的选项可供选择),您可以阅读有关 here 的信息。

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

【讨论】:

以上是关于python会自动垃圾收集双向链表吗? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

python 自动回收机制

简单说明PHP的垃圾收集机制是怎样的?

GC算法

我们可以使用类编写链表吗?不使用结构? [复制]

JVM-03

Java垃圾回收算法