Live data from Hacker News

Go does not need a Java-style GC

erik-engheim.medium.com

61–70 of 226 posts

Re: Go does not need a Java-style GC

#61

Earlier quoted context omitted.

This is a bit of a tangent, but you can get into situations where Java's memory-overhead becomes pretty untenable. I was in a situation of having to keep track of ~1 billion short strings of a median length of maybe 7 characters. In terms of just data, that should clock in at about 10 Gb; in practice it was closer to 24 Gb. I tried going with just byte[]-instances instead, which didn't help a lot. Using long byte[]-i…

I would never write something like this in java, but to be fair, a program shouldn't be written like this in the first place. If you "need" a billion strings in memory and you didn't design for that with something that would scale better, you messed up a long time ago.

Huh, I didn't really have a problem solving the problem as it came up. Like many scaling problems, it wasn't a problem until it was. Then I fixed it. Now I have a solution that can deal with ten times as many strings as before. If I grow out of that one, I'll come up with a better design.

I could have gotten 10 times as much hardware instead, but that would be an incredible waste of money compared to just spending a few days writing more hardware-efficient code.

Re: Go does not need a Java-style GC

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

I agree. The author seems to know quite a bit about Go and GCs, but doesn't seem to have much experience with Java. As a Java performance engineer, it sounds like he is comparing Go to how he thinks Java works based on what he's read about it.

Additionally he doesn't seem to know that much about C#, which also has advanced GC, while allowing for C++ like memory management, if needed.

Re: Go does not need a Java-style GC

#64
post #56

Earlier quoted context omitted.

This is a bit of a tangent, but you can get into situations where Java's memory-overhead becomes pretty untenable. I was in a situation of having to keep track of ~1 billion short strings of a median length of maybe 7 characters. In terms of just data, that should clock in at about 10 Gb; in practice it was closer to 24 Gb. I tried going with just byte[]-instances instead, which didn't help a lot. Using long byte[]-i…

FWIW. This would probably present a challenge in most (all?) languages. For example in libc++ due to SSO an std::string has a minimum size of 24 bytes. For a billion strings less than 15 chars (+ the null byte) that gets you to 24GB, and that’s optimistically assuming each string is allocated in place. I doubt heap allocated char* would do much better either. Just having a billion 8 byte pointers eats a lot of memory…

It's a lot easier to build custom allocators in C++ though.

For one, Java has a maximum mmap-size of 2 Gb, and as a cherry on top of that turd, you have no control over their lifecycle. The language is very clearly not designed for this type of work, and if you try to make it do it anyway, it fights you every step of the way.

Re: Go does not need a Java-style GC

#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 any struct and still pass pointers to it to non-inlined functions.

Re: Go does not need a Java-style GC

#66
post #11
post #4

What it needs is Rust style static lifetime management.

As a Rust developer, contributor and generally a big fan of Rust, I'd tend to disagree. Having a garbage-collector is a lifesaver for many algorithms. Static lifetime management is great but isn't something you want to force developers to use when they're more interested in coming up with solutions quickly. Also, I really don't see how it would work in Go. You require a pretty strong type system to make static lifeti…

If you're at the point that serious GC performance is being examined, then a rewrite to rust is something that should be considered on the strategic roadmap if it is code you have control over (versus third party / OSS software).

I think Go has a maximum expansion footprint. People presumably use Go because it is faster and better GC than Java. Rust will probably eat a lot of that territory. That will leave people that like it strictly for language/idiomatic reasons, and that won't be enough.

The entire meta-point of the post is to try to argue that Go is "better" than Java GC-wise. Well, it is and it isn't in reality, as benchmarks and people in the know have said. If it is "better" it is a very unconvincing win.

As someone wise said 10 years ago, you almost need 10x the performance to have a convincing improvement to get laypeople to notice, and to get dev people to consider switching from legacy/entrenched ways of doing things.

Here, there's basically no real world improvement to point to.

Re: Go does not need a Java-style GC

#67

As some of the other comments in the thread allude, this is quite a rudimentary (or rather outdated) understanding of how Java GC operates and ends up (unfortunately) turning an otherwise good comparison into a straw-man argument. As someone who's worked with Java from the days where "If you want superhigh performance from Java without GC pauses, then just turn off GC and restart your process every X hours" was consi…

Fundamentals of Java about data/class layouts in memory have remain same for decades. So author is right at big picture.

> I think the changes Java has made to GC are among the biggest improvements to the framework/JVM and have contributed vastly to JVM stability and growth over the last decade.

This is of course true. However the point is for Java it is absolute necessity for Go it may be nice to have.

Re: Go does not need a Java-style GC

#68

This is mostly stupid. Being able to have many GCs is a good thing. The big reason for "value types" is controlling spacial locality in memory, not GCs being bad per-se. Also, they undersell the java/c# situation. C# has "ref, out, or in", but even without those, you can always make a reference wrapper that has the value type as a field. So "reference types suck because coppying" is nonsense garbage.

I mean, I’ve dabbled in all of these languages, and I much prefer Go’s value types to ref, out, in, and a half dozen GCs. It’s nice that these VM languages have a distinct thing for every eventuality, but I much prefer a single thing that works 99% of the time.

I usually am bashing Go :D, but I am not this time.

I am saying this blog author is confused on what the runtimes are capable of. I don't mean to say ref out and in are good language ergonomics or whatever, but simply that they show the compilation target is capable of expressing thing these things.

The only thing I know of that the go runtime can do that these others can't is "interior pointers", i.e. pointers to a field of a larger object. You can always just copy the field into a new box, but that breaks mutation semantics. Java gets away with this precisely because most fields are themselves boxed...bu that's exactly the no-control-over-locality problem we're trying to solve.

Re: Go does not need a Java-style GC

#69
post #55
post #13

Earlier quoted context omitted.

ZGC[4] in particular has me excited, enough so to want to pick up a JVM language.

ZGC and Shenandoah can be slower than G1, those are not silver bullets. The fact that there is 4-5 GCs explains the situation, there is not a single GC that is better than the others. It really depends of the workload.

Indeed. It is strange that no official JDK document puts pros/cons of GCs packaged with standard JDKs in some kinda easy-to-read table/matrix.

Re: Go does not need a Java-style GC

#70

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…

[deleted]
Post reply on HN