链接节点 类 中的内存泄漏

Memory leaks in classes of linked nodes

我正在尝试在 python 中重新实现(再一次……我知道……)一个由节点 类 构成的简单网络,该节点引用其他节点 类(他们 children),我想知道如果我创建一个递归网络 (node1 -> node2 -> node3 -> node1) 并意外丢失对任何节点的所有引用会发生什么。

假设我有以下代码

class node():
    def __init__(self):
        self.children = []

    def append(self, child):
        self.children.append(child)

node1 = node()
node2 = node()

node1.append(node2)
node2.append(node1) # now the network is recursive

node1 = 0
# node1 is still referenced in node2.children so will not be deleted
node2 = 0

# now both node1 and node2 are not directly referenced by any variable
# but they are referenced by the two children instances

在最后一行代码之后,所有对 node1 和 node2 的引用都丢失了,但是最初分配给节点的内存仍然包含对它们自己的引用。

node1和node2还会被销毁吗?

是的,对象将被垃圾回收。垃圾收集器将检测循环引用并将其中断,以便可以进行正常的引用计数清理。见 gc module.

如果您的 node class 实现了 __del__ 方法并且您使用的是 Python,您 遇到问题版本 < 3.4。在 3.4 中现在可以 break circular references involving instances with __del__ methods 在大多数情况下。

来自object.__del__ documentation

Note: del x doesn’t directly call x.__del__() — the former decrements the reference count for x by one, and the latter is only called when x‘s reference count reaches zero. Some common situations that may prevent the reference count of an object from going to zero include: circular references between objects (e.g., a doubly-linked list or a tree data structure with parent and child pointers); a reference to the object on the stack frame of a function that caught an exception (the traceback stored in sys.exc_traceback keeps the stack frame alive); or a reference to the object on the stack frame that raised an unhandled exception in interactive mode (the traceback stored in sys.last_traceback keeps the stack frame alive). The first situation can only be remedied by explicitly breaking the cycles; the latter two situations can be resolved by storing None in sys.exc_traceback or sys.last_traceback. Circular references which are garbage are detected when the option cycle detector is enabled (it’s on by default), but can only be cleaned up if there are no Python-level __del__() methods involved. Refer to the documentation for the gc module for more information about how __del__() methods are handled by the cycle detector, particularly the description of the garbage value.