I suppose it would need to be compacting; Go seems to get along okay without compaction, presumably because it has value types?
Go has traded throughput for latency. The throughput of a semispace copying collector is very high for most workloads, but can suffer latency issues. There is literally zero cost to collecting garbage in the nursery with the algorithm described in TFA (a nursery collection has a cost proportional only to the live data), and the cost of allocating in the nursery is just incrementing a single value. However eventually you need to collect the entire heap, and it's still proportional to the size of the live data, which is usually the majority of the heap (since you've already collected the nursery at that point).
Sorry, I'm confused. Is Go's GC the semispaced copying collector or the TFA? Or neither? Or both?
TFA == "The Fine Article" so refers specifically to the Erlang Garbage Collector.
"Semispace" is one term to refer to the family of garbage collectors that Erlang's derives from. The heap is divided into two spaces, hence "semispace"
So Go's GC is neither. Go's gc is tuned for lower latencies, and that tends to rule out moving collectors (there are ways of having incremental moving collectors, but they complicate the runtime a bit).
Ah, thanks for the information and clarification!
Go trades the complexity of a compacting GC for forcing you to restart the app regularly if you have a workload with plenty of heap allocation.
Really? I've never heard anyone mention this and I've followed Go for years.
Yeah, it mostly happens when you have a server which runs an abnormally large task or payload, causes the heap to grow, and does it in a way that Go can't release the memory back to the OS due to heap fragmentation.
I haven't looked at this for a while but I believe it's still an issue.
https://github.com/cockroachdb/cockroach/issues/2007 https://github.com/golang/go/issues/18896 https://github.com/golang/go/issues/14045
Concurrent compacting collectors are pretty tough however, and a single process STW should be much faster than a global one, since it will be (at worst) proportional in time to the per process heap size.