HackerTrans
TopNewTrendsCommentsPastAskShowJobs

mknyszek

no profile record

comments

mknyszek
·4 miesiące temu·discuss
I think this is a misunderstanding. If the program out-paces the GC because the GC guessed the trigger point wrong, something has to give.

In Go, what gives is goroutines have to use some of their time slice to assist the GC and pay down their allocations.

In Java, I believe what you used to get was called "concurrent mode failure" which was somewhat notorious, since it would just stop the world to complete the mark phase. I don't know how this has changed. Poking around a little bit it seems like something similar in ZGC is called "allocation failure"?

The GC assist approach adopted by Go was inspired by real-time GC techniques from the literature and in practice it works nicely. It's not perfect of course, but it's worked just fine for lots of programs. From a purely philosophical point of view, I think it results in a more graceful degradation under unexpectedly high allocation pressure than stopping the world, but what happens in practice is much more situational and relies on good heuristics in the implementation.
mknyszek
·4 miesiące temu·discuss
> Thus, they’ll probably never fix it.

I'm sorry you had a bad experience with Go. What makes you say this? Have you filed an issue upstream yet? If not, I encourage you to do so. I can't promise it'll be fixed or delved into immediately, but filing detailed feedback like this is really helpful for prioritizing work.
mknyszek
·4 miesiące temu·discuss
The compiler generates code to spill arguments to the stack at synchronous preemption points (function entry). Signal-based preemption has a spill path that saves the full ABI register set.
mknyszek
·w zeszłym roku·discuss
Yep! I was on my phone, sorry about that.

Did it ever used to only show wall time? Or am I just completely misremembering?
mknyszek
·w zeszłym roku·discuss
Fascinating. I could see the Serial GC, if it's generational, just totally crush this particular benchmark. I wonder what the heap size heuristic is for the Serial GC.

> Don't forget that the JVM has to allocate memory for all its subsystems as well, like the JIT compiler, so that 3x memory is not entirely heap usable by the program.

That's fair. I recall doing my due diligence here and confirming it is actually using mostly heap memory, but again it's been a while and I could be wrong. (Also if the actual heap size is only ~100s of MiB and the rest of the subsystems need north of a GiB, that's much more than I would have anticipated.)

> And I deliberately linked this benchmark, as the topic at hand is the GC itself.

Sure. Not trying to suggest the benchmark doesn't have any utility, just that even for just GC performance, it doesn't paint a complete picture, especially if you're only looking at wall time.
mknyszek
·w zeszłym roku·discuss
I just meant that you cannot easily see wall time and memory use together on the same page. (I would love to be wrong about that.)
mknyszek
·w zeszłym roku·discuss
Looking at only the CPU numbers from this benchmark is misleading. This site requires the use of default configurations for each language runtime, and JVMs tend to have a much larger default heap than the Go runtime. Tracing GCs tend to have a CPU/memory tradeoff built into them [1]. Compare the memory footprint of the best Go and best Java programs in terms of wall time [2] (the site doesn't make it easy, you have to go back and forth between the two links) and the difference is enormous (these Go programs are running with much smaller total heap sizes, so much less runway for the GC).

If you use GOGC and GOMEMLIMIT to even the playing field (and note, use a Go program that isn't using sync.Pool) the difference in wall time is far less stark (though it's still there, maybe 5-15%; don't quote me, it's been a long time since I measured this and I don't remember exactly). (The difference in total CPU time is bigger.)

And finally, keep in mind this benchmark is hammering as hard as it can on the GC. How it impacts real applications depends on how much the application relies on the heap.

[1] https://go.dev/doc/gc-guide#Understanding_costs

[2] https://benchmarksgame-team.pages.debian.net/benchmarksgame/...