Live data from Hacker News

Go does not need a Java-style GC

erik-engheim.medium.com

71–80 of 226 posts

Re: Go does not need a Java-style GC

#71
post #43

Earlier quoted context omitted.

Even if it doesn't need specifically a compacting QC having a swappable more tunable one might still be a big deal for people who need something other than the current GC. Like a simple example is the Discord article about how their use case could not work with Go because it always ran the GC every two minutes. If they could optionally disable that feature they theoretically could have kept using Go instead of rewrit…

The go gc was greatly improved in the versions subsequent to the ones used by Discord. The timing there was unfortunate.

Besides sometimes engineers just want to use Rust.

Re: Go does not need a Java-style GC

#72

> 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…

    Point[] array=new Point[15000];
In java would create an array with null references, to fill it up you need to create each object so that point is valid.

Re: Go does not need a Java-style GC

#73

Earlier quoted context omitted.

Go creates less garbage and also stack allocates things using escape analysis which as the article explains, is effectively a form of generational garbage collection.

However it's a weak one, the stack allocation acts as a form of extremely limited nursery, but lots of "escaping" objects could well fit into a nursery, to say nothing of "heap" objects (like strings and slices) which always trigger heap allocations. Furthermore AFAIK most generational GCs have 3 generations, not 2 (let alone 1.5). It does make the tradeoff more complicated, a generational GC is not simple (especiall…

> Go users have to work around using ugly hacks when hit, because they don't have tuning knobs

Yeah, Java users just have to hire Java performance tuning experts from sprawling Java perf consulting cottage industry. Can't get much simpler than that.

Re: Go does not need a Java-style GC

#74
post #65
post #6

> In a multithreaded program, a bump allocator requires locks. That kills their performance advantage. Java uses per-thread pointer bump allocators[1] > While Java does it as well, it doesn’t utilize this info to put objects on the stack. Correct, but it does scalar replacement[2] which puts them in registers instead > Why can Go run its GC concurrently and not Java? Because Go does not fix any pointers or move any o…

"Scalar replacement" explodes the object into its class member variables and does not construct a class object at all. That does result in the exact same `sub %esp` (that Go would do for any struct), but it is restricted to only working if every single usage of that class type is fully inlined and the class is never passed anywhere that needs it in its object form. It's worse than what Go has. Go can stack-allocate a…

Scalar replacement does not work even in very trivial cases: https://pkolaczk.github.io/overhead-of-optional/

In all those cases, Optionals were inlined, didn't escape, yet they haven't been properly optimized out.

Re: Go does not need a Java-style GC

#76

The binary-trees benchmark on The Debian Language Shootout[1] involves allocating millions of short-lived trees and traversing them. It is informative about GC performance even with the caveat that there are 'lies, damned lies, and benchmarks', because many real-world graph analysis and brute force tree search algorithms similarly allocate zillions of short-lived nodes. For non-GC languages like C/C++/Rust it gives a…

> So Java has the fastest GC for this test, 2.48 secs vs 12.23 secs for Golang.

Further not mentioning memory used Java/Go programs makes it very fair comparison. Because GC perf does not depend on memory allocated.

Re: Go does not need a Java-style GC

#77
post #10

Cool article, I'm not sure I agree with the headline. I used to write low-scale Java apps, and now I write memory intensive Go apps. I've often wondered what would happen if Go did have a JVM style GC. It's relatively common in Go to resort to idioms that let you avoid hitting the GC. Some things that come to mind: * all the tricks you can do with a slice that have two slice headers pointing to the same block of memo…

Java has a pretty decent standard library with different list, map and set implementations and quite a few third party libraries with yet more data structures. Honestly, Go felt a bit primitive and verbose to me on that front on the few times I used it. Simplicity has a price and some limitations. There are also other tricks you can do like for example using off heap memory (e.g. Lucene does this), using array buffer…

> There even have been some attempts to make Go run on the JVM. Apparently performance, concurrency and memory management were big motivators for attempting that (you know, stuff the JVM does at scale):

This seems legit. Just links to their website/Wiki are not working right now.

Re: Go does not need a Java-style GC

#78
post #10

Cool article, I'm not sure I agree with the headline. I used to write low-scale Java apps, and now I write memory intensive Go apps. I've often wondered what would happen if Go did have a JVM style GC. It's relatively common in Go to resort to idioms that let you avoid hitting the GC. Some things that come to mind: * all the tricks you can do with a slice that have two slice headers pointing to the same block of memo…

Java has a pretty decent standard library with different list, map and set implementations and quite a few third party libraries with yet more data structures. Honestly, Go felt a bit primitive and verbose to me on that front on the few times I used it. Simplicity has a price and some limitations. There are also other tricks you can do like for example using off heap memory (e.g. Lucene does this), using array buffer…

Not sure if you're in on the joke, but for those who didn't go to the repo itself:

https://github.com/golang-jvm/golang-jvm

It's just a copy-paste of JRuby on April 1st and the readme now includes a rickroll.

Maybe it's irresponsible of them to leave it up in a way that Google still finds as a legitimate-looking search result.

Re: Go does not need a Java-style GC

#79

> 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…

Point[] array=new Point[15000]; In java would create an array with null references, to fill it up you need to create each object so that point is valid.

I stand corrected on that point.

Re: Go does not need a Java-style GC

#80
post #76

The binary-trees benchmark on The Debian Language Shootout[1] involves allocating millions of short-lived trees and traversing them. It is informative about GC performance even with the caveat that there are 'lies, damned lies, and benchmarks', because many real-world graph analysis and brute force tree search algorithms similarly allocate zillions of short-lived nodes. For non-GC languages like C/C++/Rust it gives a…

> So Java has the fastest GC for this test, 2.48 secs vs 12.23 secs for Golang. Further not mentioning memory used Java/Go programs makes it very fair comparison. Because GC perf does not depend on memory allocated.

Right now in the datacenter CPU usage is considerably more expensive than RAM usage. Ram consumes comparatively little power, whereas burning hot CPUs+GPUs are the reason datacenters are favored near cooling water and power stations. 2.48 vs 12.23 seconds for Java and Go is a big deal for how many solar panels or tons of coal are needed to run an app on Xeon or Epyc instances, whereas 1.7GB vs 0.4GB for Java and Go, a 4x difference in low-power memory usage, is not so big of deal.

At any rate I did link to the full table so everyone can see the mem usage, source listings, etc.

Post reply on HN