垃圾回收 / 链表

3
垃圾回收器(理论上)会收集这样的结构吗?
package main

type node struct {
    next *node
    prev *node
}

func (a *node) append(b *node) {
    a.next = b
    b.prev = a
}

func main() {
    a := new(node)
    b := new(node)
    a.append(b)
    b = nil
    a = nil
}

这应该是一个链表。 a 指向bb 反过来指向 a。当我删除ab的引用(最后两行),这两个节点将不再可访问。但每个节点仍然有一个引用。那么,go垃圾回收器仍然会移除这些节点吗?
(显然不是上面的代码,而是在长时间运行的程序中)。
是否有处理这些问题的垃圾回收器文档?
2个回答

6
你的程序中垃圾收集器(GC)根集合是{a, b}。将它们全部设置为nil会使所有堆内容都有资格进行回收,因为即使现有节点被引用,但它们从任何根都不可达。
同样的原理也保证了具有循环和/或自引用的结构一旦变得不可达就会被回收。

谢谢!我会尝试更多地了解GC的一般知识和Go语言中的GC。你是否偶然知道Go语言垃圾回收器的任何文档资料? - topskip
@topskip:很遗憾,我不知道有这样的文档。它曾经是一个保守的GC,目前它主要是一个精确的GC,只剩下少数几个地方(我认为调用记录[堆栈帧]还不是精确的)。 - zzzz

4
您描述的问题实际上是一种简单但很少使用的垃圾回收方案所存在的真正问题,称为“引用计数”。基本上,就像您所暗示的那样,垃圾回收器(GC)会计算有多少个引用指向给定对象,并且当该数字达到0时,它将被清除。而且,确实,循环引用将防止引用计数系统对该结构进行垃圾回收。
相反,许多现代GC(包括Go;请参见this post)采用一种称为”标记-清除”的过程。基本上,所有顶级引用(在某个函数范围内拥有的指针)都被标记为“可达”,然后所有从这些引用引用的东西都被标记为可达,以此类推,直到所有可达对象都被标记。然后,任何未被标记的东西都被认为是不可达的,并被清除。循环引用不是问题,因为如果它们没有从顶级引用引用,它们将不会被标记。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接