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?
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.
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.