Note this is all about OpenJDK and Project Leyden.
There are plenty of other AOT/JIT cache approaches in the Java ecosystem already, with more mature deployment experience of several years, namely:
OpenJ9, Azul, PTC, Aicas, the Android cousin since Android 7
Technology based on process snapshots CRaC for Amazon OpenJDK distro (Correcto), and OpenJ9, is also another approach available for some time.
I spent a couple weeks trying to bolt this on to our setup to support a more serverless style approach. OpenJ9 (sadly) really didn't work out well, perhaps we run in a way they don't optimize for. Azul and OpenJDK's approaches helped - but it is quite intrusive (you need a profiling run), and the absolute benefits aren't that great. It's mostly doing classpath stuff at present, and not really AOT work on machine code (though that is in the pipeline).
All in all, I wasn't particularly impressed with the outcome. Obviously GraalVM has more headroom, but that's an even more intrusive change.
When compared with a Rust port of our service, the delta of the efforts is absolutely astronomical. Ridiculous performance, near-instant startup, radically less memory consumption. I mean - duh - but nonetheless, when I contrast the effort vs payback, it's very hard for me to want to invest so much in techniques that have so little payback (graal) when I can put that into an approach that leaves me in a much better place long-term.
If I had mountains of legacy, obviously I couldn't do that, but in my situation it seems like a much more attractive option.
Are you arguing it's less work to rewrite your entire app in Rust than to use GraalVM Native Image? Because you can get C/Rust style startup time and less memory usage with the latter, but it should take an agent only a few minutes to get things working (unless you are using a lot libraries that spin bytecode, but there is a mode for native image coming that can fully handle bytecode generation and can run any Java app).
> Ridiculous performance, near-instant startup, radically less memory consumption.
It seems like your use case is rather not a good fit for Java.
Java shines best with large applications, where more abstract source code is desired and when you care more about typical performance, not the worst case performance. And if you can afford the cost of all those benefits, which is higher RAM usage.
At least that's the theory :)
It's not like typical performance of Java is great and only GC pauses (or whatever) drag it down. In other words, Java is no match for Rust / C / C++ even comparing "good runs only" of both.
There are no GC pauses in modern Java implementations, and there are plenty of systems written in C and C++ that have been replaced by Java, I took part in such projects.
Companies like PTC and Aicas stay in business, because there are plenty of industries that pay for their embedded JVM implementations instead of keeping legacy C and C++ infrastructure running.
Every GC in Java involves synchronization points and the pausing of application threads.
I'm arguing against "Java performance is as good as it gets" in this thread, but the best Java GCs have sub-millisecond pause times for huge heap sizes and, apparently, such a GC even became the default recent-ish-ly: https://inside.java/2023/11/28/gen-zgc-explainer/
The JVM is amazing technology for what it is, but what it is still limits how fast it can go.
[flagged]
Not every GC, better learn the ecosystem.
Provide the GC name.