英文:
Garbage collection / linked list
问题
垃圾收集器理论上会收集这样的结构。在你提供的代码中,这是一个链表。a
指向b
,b
又指回a
。当我移除a
和b
中的引用(最后两行),这两个节点将不再可访问。但是每个节点仍然有一个引用。垃圾收集器会移除这些节点吗?(显然不是在上面的代码中,而是在一个运行时间较长的程序中)。
关于处理这些问题的垃圾收集器的文档是否存在?
英文:
Will the garbage collector (in theory) collect a structure like this?
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
}
This should be a linked list. a
points to b
, b
points back to a
. When I remove the reference in a
and b
(the last two lines) the two nodes are not accessible any more. But each node still has a reference. Will the go garbage collector remove these nodes nonetheless?
(Obviously not in the code above, but in a longer running program).
Is there any documentation on the garbage collector that handles these questions?
答案1
得分: 6
你的程序中垃圾收集器(GC)的根集是 {a, b}。将它们全部设置为 nil 会使得所有堆内容都符合回收条件,因为现在所有现有的节点,即使它们被引用,也无法从任何根节点访问到。
同样的原理也适用于具有循环引用和/或自引用的结构,一旦它们变得不可达,就会被回收。
英文:
The set of garbage collector (GC) roots in your program is {a, b}. Setting all of them to nil makes all heap content eligible for collection, because now all of the existing nodes, even though they are referenced, are not reachable from any root.
The same principle guarantees also for example that structures with circular and/or self references get collected once they become not reachable.
答案2
得分: 4
你描述的问题实际上是一个与一种简单但很少使用的垃圾回收方案——"引用计数"——有关的真实问题。基本上,就像你所暗示的那样,垃圾回收器(GC)计算对给定对象存在多少引用,当该数字达到0时,就会进行垃圾回收。确实,循环引用将阻止引用计数系统对该结构进行垃圾回收。
相反,许多现代的垃圾回收器(包括Go语言;参见这篇帖子)采用一种称为"标记-清除"的过程。基本上,所有顶层引用(在某个函数的作用域中拥有的指针)都被标记为"可达",然后所有从这些引用引用的东西都被标记为可达,依此类推,直到所有可达对象都被标记。然后,未被标记的任何东西都被认为是不可达的,并进行垃圾回收。循环引用不是问题,因为如果它们不是从顶层引用引用的,它们就不会被标记。
英文:
The concern you describe is actually a real problem with a simple but little-used garbage collection scheme known as "reference counting." Essentially, exactly as you imply, the garbage collector (GC) counts how many references exist to a given object, and when that number reaches 0, it is GC'd. And, indeed, circular references will prevent a reference counting system from GC-ing that structure.
Instead what many modern GCs do (including Go; see this post) is a process known as mark-and-sweep. Essentially, all top-level references (pointers that you have in the scope of some function) are marked as "reachable," and then all things referenced from those references are marked as reachable, and so on, until all reachable objects have been marked. Then, anything which hasn't been marked is known to be unreachable, and is GC'd. Circular references aren't a problem because, if they aren't referenced from the top-level, they won't get marked.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论