Hacker News new | ask | show | jobs
by cyberax 589 days ago
> Am I the only one?

Probably not. Java had stagnated for quite a while, entirely missing the lightweight threading and/or async/await revolution of the last decade. The JVM ergonomics also just sucks, a lot of apps _still_ have to use -Xmx switches to allocate the RAM, as if we're still using a freaking Macintosh System 6!

On the other hand, it's a very mature ecosystem with plenty of established battle-tested libraries.

5 comments

Java is one of the couple of platforms that do have virtual threads (others being Erlang, go and Haskell), and by far the biggest among these..

Is it not you who stagnated a bit?..

I think your information is outdated. Java has had lightweight threads for several releases now. It also has type pattern matching switches, and a bunch of modern ergonomics.

async/await is not really a revolution, so much as a bandaid bringing a modicum of parallelism to certain programming languages that don't have a good threading model.

Xmx is mostly a thing if you have very small RAM, or some sort of grievously misconfigured container setup. By default it grow up to 25% of the system RAM, which is a relatively sane default.

> I think your information is outdated. Java has had lightweight threads for several releases now.

Well, yes. It was released as a part of JDK 21 a year ago. So far, the adoption has been spotty. They are also implemented not in the best possible way.

> Xmx is mostly a thing if you have very small RAM, or some sort of grievously misconfigured container setup. By default it grow up to 25% of the system RAM, which is a relatively sane default.

Other more sane runtimes (like Go) do not even have developers care about the heap sizing. It just works.

It’s valid criticism because you do need to think about it less in other runtimes, but it doesn’t always just work. There’s a reason why GOMEMLIMIT and other knobs for high allocation programs were introduced.

IIRC .NET just sets it to 75% of available memory.

> IIRC .NET just sets it to 75% of available memory.

Out of all three Go one is the least configurable. .NET GC is host-memory aware and adjusts heap size automatically. It does not need Xmx as it targets to keep host memory pressure low but the hard limit really is only available memory unless you override it with configuration.

It has been further improved as of recently to dynamically scale heap size based on allocation rate, GC % time and throughput targets to further reduce sustained heap size.

Java does the sane thing within containers, and you definitely not have to set memory settings anywhere else, unless you want some very specific behavior.
I thought this was the case but actually couldn’t find any documentation on it. The best I could find was that the vm is aware it is in a container and will correctly set the heap %’s based on the containers memory. It still looked like it was defaulting to 25%.
The async/await is not a revolution, but rather is a tool only for specific use cases. It shouldn't be used by default, as it makes the project unnecessarily complicated. If your requirements are to do heavy parallelism where everything uses I/O, then use async, but for the rest of cases? Probably not worth it.
The revolution is the need for massive concurrency. It doesn't need to be async/await, Go-like green threads are even better.
> ...entirely missing the lightweight threading...

They deliberately took the longer route, aiming to integrate lightweight threads in a way that doesn't force developers to change their existing programming model. No need for callbacks, futures, coroutines, async/await, whatever. This required a massive effort under the hood and rework to many core APIs. Even code compiled with decade old Java versions can run on virtual threads and benefit, without any refactoring or recompilation.

> ...and/or async/await revolution of the last decade

async/await is largely syntactic sugar. Java has had the core building blocks for asynchronous programming for years, with CompletableFuture (2014, replacing the less flexible Future introduced in 2004) and NIO.2 (2011, building on the original NIO from 2002) for non-blocking I/O, along with numerous mature libraries that have been developed on top of them over time.

Omg I forgot about that. So there’s no way to say just grab the memory you need and that’s that?
That’s in the works, where it adapts from 16mb to terabyte heaps. The current GCs have a max, with lazy allocation and ability to release back to the system periodically, but are not as system aware.

1. https://openjdk.org/jeps/8329758

2. https://m.youtube.com/watch?v=wcENUyuzMNM&embeds_referring_e...