Hacker News new | past | comments | ask | show | jobs | submit login

It takes a lot of power to push something that large. A lot of brain power to grock the ecosystem.

Outside of the Java bubble, the view is quite a bit different.

All that sophistication looks like a wasted effort.

Take something as simple as admining the garbage collector. Java has a big selection of GCs, and each has their bunch of knobs for tuning. And you have to pay attention to that stuff.

After working with Go for several years, at large scale, we never once had to touch any knobs for GC. We could focus on better things. Any of the Java stuff we deploy and deal with we have this extra worry and maintenance issue.

And that's just the GC.






Funnily enough, Go just chose to solve the problem the other way around: While JVM tackled GC with the code equivalent of lightsaber-equipped drones, Go‘s GC is almost embarrassingly simple in comparison (although it‘s pretty decent by now).

The major difference is that the whole Go language and stdlib is simply written around patterns that avoid allocations almost magically. The simplicity of the Reader and Writer concepts is so elegant, yet powerful and doesn‘t allocate anything but a tiny reused buffer on the stack. There‘s lots and lots of other examples, but if you have to collect ten times less garbage, you‘ll be better off, even if your GC is 2x slower.


The byte buffers that Go's Reader reads from and that Go's Writer writes into cannot in general be allocated on the stack because they are considered to escape. Because Reader and Writer are interfaces, calls are dispatched virtually, so escape analysis cannot always see through them. This is now fixed for simple cases in Go, but only very recently: https://github.com/golang/go/issues/19361

Ironically, Java HotSpot handles the use case of Reader and Writer better than Go does, since when it's not able to allocate on the stack it has fast allocation due to the use of a generational GC with bump allocation in the nursery. By virtue of the fact that it's a JIT, HotSpot can also do neat things like see that there's only one implementation of an interface and thereby devirtualize calls to that interface (allowing for escape analysis to kick in better), something Go cannot do in general as it's an AOT compiler.


> like see that there's only one implementation of an interface and thereby devirtualize calls to that interface

Oh, the JIT devirtualizes and inlines even if there are many implementations, but only one or two at a particular callsite. This has been generalized in Graal/Truffle so you almost automatically get stuff like this (https://twitter.com/ChrisGSeaton/status/619885182104043520, https://gist.github.com/chrisseaton/4464807d93b972813e49) by doing little more than writing an interpreter.


I agree it's impressive that Go manages to be not all that much slower than Java while having a much simpler runtime, but much of the simplicity is gained from lacking features that are very important in many cases of "serious software" like deep low-overhead continuous profiling and ubiquitous dynamic linking.

I’ve seen you mention the superior operability of Java and the JVM in high load production environments and I think this is a really important, often overlooked, and commonly misunderstood point.

Would you be up for writing a short post or blog post going into some anecdotal comparisons and sharing some resources?


Exactly. Go is benefiting from years of hard lessons learned in other stacks such as Java. Having super experienced GC builders involved early on resulted in a language and libraries that work much more synergisticaly with the GC.

It's better to dodge a problem, than to have a baked in problem that requires lots of really smart people to make work arounds.


Java HotSpot's garbage collector is significantly better for most workloads than that of Go, because it takes throughput into account, not just latency. Mike Hearn makes the point at length in this article: https://blog.plan99.net/modern-garbage-collection-911ef4f8bd...

I predict that over time Go's GC will evolve to become very similar to the modern GCs that Java HotSpot has. Not having generational GC was an interesting experiment, but I don't think it's panned out: you end up leaning really heavily on escape analysis and don't have a great story for what happens when you do fail the heuristics and have to allocate.


> I predict that over time Go's GC will evolve to become very similar to the modern GCs that Java HotSpot has.

At which time the talking point will become "look how advanced and sophisticated it is!"


> Java has a big selection of GCs, and each has their bunch of knobs for tuning. And you have to pay attention to that stuff.

You never have to touch them in the Java world either, unless you like making performance worse that is.

I've never ever seen a case where fiddling with garbage collection parameters didn't make things slower.

I worked with a guy who worked on a popular java compiler, and he says the same thing. he never twiddles GC parameters either.


What sort of scale are you working at? At our scale, it is normal to look into these sorts of things. Reading and understanding and applying articles like the following is absolutely necessary.

http://clojure-goes-fast.com/blog/shenandoah-in-production/


Medium scale. It's not like I need to pimp each of my servers like it's a Honda Civic.

If the load gets too high, I just add another instance.

It's way more economical than wasting developer time fiddling with GC params.


Are you serious? You have to mess with the maximum memory allocated to the GC all the time with java processes. Also the JVMs default settings basically assume it is the only process running. It will keep hogging a huge amount of memory even if the memory allocated to the GC is 60% empty unless you configure the GC properly. Wasting memory and stealing it from other processes which potentially causes swapping or crashing is far worse than any increased time spent garbage collecting. Unless you're as stupid as the Minecraft developers you will rarely suffer from GC pressure with heaps below 10GB.

Cassandra has benefitted from so many GC tweaks that I find this view hard to believe.

i can only imagine someone having this view if they have never cared about latency. How have you never experienced a multi-second GC pause on default CMS settings?


> Outside of the Java bubble, the view is quite a bit different.

I know that outside the "Java bubble" less advanced platforms are often good enough (BTW, while Java's GC ergonomics are getting better, I agree there may be more of a paradox of choice issue, but while you may not need to touch any knobs, you're also not getting low-overhead, deep production profiling and many of the other amazingly useful things you get with Java), and even inside the Java bubble we don't think Java is always the best choice for everything, but that doesn't mean that Java isn't leading in technological innovation, which was my main point.


I'm not saying I disagree but for a lot of businesses (even one with relatively high traffic) it is not unheard of to deploy with almost no tuning of the GC (aside from setting a heap min / max of 2,4,8GB) and have no issues.

I'm sure this all depends on use-cases, but I'll chime in to agree. I work on web services that do high (not Google high, but you've-heard-of-it high) levels of traffic, we run on the JVM, and GC pauses are not something that cause us to lose any sleep using out-of-the-box settings + explicit heap min/max.

Tuning GC is hard, and the nondeterminism is worrisome, but hitting a pathological case and rewriting a bunch of code hoping to avoid it is even harder.



Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: