News for hackers. Stuff that matters.
Re:Baffled by generational garbage collection – wingolog by kgeist on Sunday February 09, 2025 @12:13PM (#42991938)
IIRC Go has "GC assist" which forces goroutines that allocate too frequently to assist in GC work (share CPU time, i.e. they're slowed down), and I've never seen anything like that described for Java/C#. Interesting approach.
Re:Baffled by generational garbage collection – wingolog by gf000 on Sunday February 09, 2025 @12:28PM (#42992027)
In other words, it slows down the user's code randomly. I wouldn't call that a necessarily good tradeoff.
Re:Baffled by generational garbage collection – wingolog by kgeist on Sunday February 09, 2025 @12:28PM (#42992031)
It's a back-pressure mechanism. I think slightly slower code on average is better than unexpected long GC pauses.
Re:Baffled by generational garbage collection – wingolog by gf000 on Sunday February 09, 2025 @12:37PM (#42992088)
But an important code that has to allocate a lot will be disproportionately affected by this. Also, it doesn't solve "unexpectedly long GC pauses" just somewhat lowers their frequency.

Java's ZGC is multiple generations ahead, and I believe is a fairer tradeoff (overall lower throughput (due to read barriers over write barriers), but guaranteed <1ms pause time due to basically everything happening concurrently)

Re:Baffled by generational garbage collection – wingolog by kgeist on Monday February 10, 2025 @03:37AM (#42998085)
Go's garbage collector is concurrent, too. GC assist makes sure the GC can keep up with allocations.
Re:Baffled by generational garbage collection – wingolog by gf000 on Monday February 10, 2025 @03:44AM (#42998125)
Correct me if I'm wrong, but concurrent GC only means that certain phases of GC can be done in parallel.

GC pauses are a necessity exactly for the part that can't be done in parallel, and Go is definitely not using ZGC's next-generation design that would decouple the pause's length from the heap size, so we still have our "arbitrary long pause" problem on the table.

Re:Baffled by generational garbage collection – wingolog by kgeist on Monday February 10, 2025 @04:08AM (#42998317)
From Go's docs:

>The Go GC avoids making the length of any global application pauses proportional to the size of the heap, and that the core tracing algorithm is performed while the application is actively executing.

>Brief stop-the-world pauses when the GC transitions between the mark and sweep phases.

I didn't benchmark it myself, though. Go is mostly used in stateless microservices where huge heap sizes are very uncommon. We usually scale horizontally, not vertically. Plus, Go has value objects which can be allocated on the stack or embedded inside other objects, so it allocates far less garbage than Java. So practically for me Go's GC has been a non-issue, I barely remember it exists.

Re:Baffled by generational garbage collection – wingolog by yvdriess on Monday February 10, 2025 @11:11AM (#43001886)
Go GC's stop the world pauses are essentially synchronization barriers at the start and end of a GC phase. That pause length is a function of the number of worker threads, not the size of the heap. You can check this yourself by running the tile38 and cockroachdb benchmarks with GODEBUG=gctrace=1 .
Re:Baffled by generational garbage collection – wingolog by gf000 on Tuesday February 11, 2025 @03:58AM (#43010553)
It's the function of both, as per even the sibling comment.

Obviously there is not much to synchronize when there is only a single thread.

Re:Baffled by generational garbage collection – wingolog by yvdriess on Monday February 10, 2025 @11:20AM (#43001994)
Any concurrent GC will have an unpredictable impact on application threads. The more obvious is the necessary synchronization on GC startup and shutdown, e.g. to turn on write barriers during GC. Less obvious but perhaps more impactful is the cache trashing incurred by the GC threads' heap traveral.