Live data from Hacker News

Go does not need a Java-style GC

erik-engheim.medium.com

171–180 of 226 posts

Re: Go does not need a Java-style GC

#171

Earlier quoted context omitted.

Scalar replacements (as currently implemented in Java) does not work in real-world programs. Well-written code does not need it. Poorly written code can not trigger it, because the JIT is too dumb and isn't getting better. There is no sane test to determine whether a piece of code will be inlined in Java. In practice anything more complex than byte array is unlikely to be inlined. Even built-in ByteBuffers aren't! Me…

The JIT is getting better. Major escape analysis upgrades are a big part of where Graal (a drop-in replacement for the HotSpot JIT) gets its performance boosts. EA definitely does work well there because Truffle depends on escape analysis and scalar replacement very heavily. GraalVM CE is better than regular HotSpot at doing it and GraalVM EE is even better again.

Graal effort is over 10 years old.

Jaotc, — Graal's sole mainstreamed part, — has been recently removed from OpenJDK in 17th release, and Oracle says [1], that they are "considering the possibility of using C2 for ahead-of-time"

1: https://mail.openjdk.java.net/pipermail/discuss/2020-Novembe...

Re: Go does not need a Java-style GC

#172
post #114

> In a multithreaded program, a bump allocator requires locks. That kills their performance advantage. Wait, what? What's wrong with: char theHeap[0x1000000]; atomic_ulong bumpPtr; void* bump_malloc(int size){ uint32_t returnCandidate = bumpPtr.fetch_add(size, std::memory_order_relaxed); if(returnCandidate + size >= HEAP_SIZE){ // Garbage collect. Super complicated, lets ignore it lol. // Once garbage collect is done…

Even with relaxed memory ordering, you’re still bouncing the cache line around between every CPU that tries to access bumpPtr. I would expect that to be significantly slower than using per-thread heaps (especially if you have a large number of CPUs).

Java bump pointer allocations (ie: normal allocations, except for eg: large array allocations) occur in a thread local allocation buffer. Only when a thread exhausts its current allocation buffer does it need to worry about potentially contending with other threads to acquire a new one.

Re: Go does not need a Java-style GC

#173
post #130

Earlier quoted context omitted.

Or being amazed by Go's compile speed, when Turbo Pascal and Object Pascal compilers were already doing that in the 1980's, or finding WASM innovative when polyglot bytecodes with no GC also go back to the early 1980's, like Amsterdam Compiler Kit EM as one example among many.

I just wrote some Go last weekend and the compile time was very slow. It reminded me of Scala. Any way I switched to Ruby and didn't have to deal with it any more. Turbo Pascal really was fast, but I don't see that in Go.

Scala and SBT are some of my biggest productivity killers. They murder my machine and take years to do compile.

Re: Go does not need a Java-style GC

#174
post #130
post #127

Earlier quoted context omitted.

It's odd how most people that haven't used a VM with GC are amazed by Go (no VM) and WASM (no GC) but still fail to understand that with a GC _AND_ VM you can code something that doesn't crash even if you make a big mistake! And they haven't even bothered to try it out! To use anything other than JavaSE/C# on the server you really need very good arguments!

Or being amazed by Go's compile speed, when Turbo Pascal and Object Pascal compilers were already doing that in the 1980's, or finding WASM innovative when polyglot bytecodes with no GC also go back to the early 1980's, like Amsterdam Compiler Kit EM as one example among many.

Not to mention Turbo Pascal was compiling faster than Go, on a single-core, in-order 20Mhz PC...

Re: Go does not need a Java-style GC

#175
post #135
post #122

Earlier quoted context omitted.

i've literally experienced worse pauses from java (sometimes surpassing 30s) GC due to allocation. granted it was pre the latest G1 GC. but they absolutely exist and many companies run on older versions of java. and I doubt you see pauses in golang longer than 30ms. proof please.

Comparing apples to oranges. Java has been around for multiple decades so there may be some bias on your part based on very old examples, but also, your “average” java program is more likely much more complex and larger code base than your average go one. Also, shitty code does get written by developers quite often, regardless of language — at that point the runtime can only do that much.

this is entirely BS. if by complex you mean overly abstracted and useless boilerplate then yes. java is larger and more complex.

and your assertion about the runtime only being able to do so much is just wrong here. golang will slow down your application in order to meet GC deadlines.

however its incredibly rare to see GC STW pauses for longer than 10s of ms. not even sure its possible given how the GC is written. this is true for heaps in the 100s of GBs.

this is why you don't hear about issues with golangs GC since like ~1.7. it just doesn't show up in 99% of use cases.

your basic assertion that java's GC is more advanced and therefor better is completely without merit. GC doesn't operate in isolation. java has more complicated GC systems because the language mandates them. golang entirely sidesteps the issues java has requiring said systems with better memory layouts and utilizing the stack.

its incredibly rare to hear stories about golangs GC because its simply not a problem.

java still has a bunch of issues and requires different GC tradeoffs as a result. meaning java will likely be in a constant state of 'which GC model do I use'

Re: Go does not need a Java-style GC

#176
post #116

Earlier quoted context omitted.

> It feels like a huge trade-off of GCs is almost completely gone. FWIW the tradeoff of low latency GC is usually paid in throughput. That is definitely the case for Go, which can lag very much behind allocations (so if your allocation pattern is bad enough the heap will keep growing despite the live heap being stable, because the GC is unable to clear the dead heap fast enough for the new allocations).

throughput can be fixed by adding compute. latency cannot. always optimize for latency with gc. and no the heap will not keep growing in golang. it'll force threads to help with GC if its falling behind. thereby reducing the rate of allocations and speeding up the collection.

Random Go dev suddenly more of an expert than the literal best-in-class GC experts that have been working on G1GC, ZGC, Shenandoah, Parallel, ConcMarkSweep and others.

GCs are a matter of tradeoffs. Always optimizing for latency is Go's solution, but there are reasons for everything. It's the very reason why the JVM has so many knobs. Yes, it requires a PhD to know what to tune, but there are many parameters for the thousands of different situations that can arise.

Re: Go does not need a Java-style GC

#177
post #116

Earlier quoted context omitted.

throughput can be fixed by adding compute. latency cannot. always optimize for latency with gc. and no the heap will not keep growing in golang. it'll force threads to help with GC if its falling behind. thereby reducing the rate of allocations and speeding up the collection.

Only in some kinds of apps, like web servers where all the heavy lifting is being done by the database anyway. Consider a compiler. It's not infinitely scalable to multiple cores. It may not even be multi-threaded at all. It also doesn't care about pause times - for that you want Parallel GC.

depends on the compiler and language. golang seems to counter point your position quite handedly. having one of the fastest compile times and being highly concurrent.

if your application is so simple it doesn't use concurrency then 99% of the time you can completely remove the need for GC by preallocating slabs.

Re: Go does not need a Java-style GC

#178
post #116

Earlier quoted context omitted.

throughput can be fixed by adding compute. latency cannot. always optimize for latency with gc. and no the heap will not keep growing in golang. it'll force threads to help with GC if its falling behind. thereby reducing the rate of allocations and speeding up the collection.

Random Go dev suddenly more of an expert than the literal best-in-class GC experts that have been working on G1GC, ZGC, Shenandoah, Parallel, ConcMarkSweep and others. GCs are a matter of tradeoffs. Always optimizing for latency is Go's solution, but there are reasons for everything. It's the very reason why the JVM has so many knobs. Yes, it requires a PhD to know what to tune, but there are many parameters for the…

rolls eyes I've tuned java's GC for highly available and massive throughput systems.

pretty familiar with the trade offs. java's problem isn't GC (in general) its problem is memory layout and the fact it can't avoid generating a metric shit ton of garbage.

G1GC was a good improvement and I stopped paying attention at that point because I no longer had to deal with its problems (left the ecosystem).

I'm not asserting java hasn't improved or that its GC implementations aren't modern marvels. fundamentally they're just a self inflicted wound.

golang wouldn't benefit anywhere near as much as java has from these implementations because guess what... they've attempted GC that operate under similar assumptions, young allocations, compacting patterns, etc. and they failed to make an improvement that just increasing the heap size knob wouldn't fix using the current GC.

Re: Go does not need a Java-style GC

#180
> In C#, for example, reference objects and value objects live entirely separate lives. Value objects are always passed by value. *You cannot take the the address of a value object and pass that around.*

The last sentence is wrong. You can pass structs by ref in C# (ref, in, out parameters). Java will also allow taking references to value types and passing them.

Post reply on HN