JEP 544: Ahead-of-Time Code Compilation
Posted by Skinney 1 day ago
Comments
Comment by rerdavies 9 hours ago
Comment by samus 8 hours ago
Comment by ptx 7 hours ago
The script wouldn't have to do the training run at install time, as I understand it, just the AOT compilation. See the section on "AOTMode=record" vs "AOTMode=create" in the JEP.
Comment by cogman10 1 day ago
The tooling for doing these sorts of training runs doesn't really exist, you end up needing to do something more bespoke as part of your build pipeline if you want it there. That can be especially tricky with more complicated applications like the ones I maintain.
I like what these can deliver, but dislike the effort needed to get it going.
Comment by elric 1 day ago
If your goal is peak performance across the board and you can't wait for runtime optimizations to kick in, you're going to have a harder time. But in many of the things I've worked on, startup time has been a bigger issue than JIT->peak.
Comment by pjmlp 1 day ago
Comment by jgon 1 day ago
Compared to Go and Rust, and just throwing a static binary to someone or some server, Java kind of sucks. And that's unfortunate because the language, the runtime, and even the dependency situation all feels pretty competent, there's not some huge gulf that makes Java "old". Its really just the every about setting up a project and then distributing it, so the "start" and "end" of a project, that currently sucks, and I fear that so much of the great work the Java team is doing is going to go largely unused if they don't work to make it easier for the average developer to utilize it.
Comment by mike_hearn 23 hours ago
I have a company that makes Conveyor, which is very good at distributing JVM apps. It's primarily meant for desktop apps and replaces jpackage with something that can cross-build, make apps self-updating, auto-minimize the bundled JDK and so on.
Adapting it for servers is something I think about sometimes, and in fact it does already support that to some extent, but it produces debs for that use case.
It's just sort of unclear what JVM developers lack here that isn't already solved by build tool plugins and Docker. Or are you thinking about CLI tooling? Because I have something cooking for that which might be pretty nice.
Comment by jgon 17 hours ago
I'm speaking more from my view as just an individual Joe Sixpack developer. If I'm not developing an enterprise behemoth, and let's just say I want to whip up a command line utility to do some image processing, or network communication, etc, Java's fantastic standard lib and ecosystem means I can do all of that pretty easily. But when I want to distribute that, what does it look like? What comes out the other side of the CI build? I have to integrate jlink with gradle, which is kind of a pain, I have to somehow integrate a training run and then package up the aot cache output and make sure that the directories are handled properly, and what do I ship to the user? A tar/zip file that they have to somehow copy and decompress to the relevant directory, maybe with #! file in .local/bin to get it on the path? By contrast the situation with Go or Rust is immensely easier, even if that actual development process may almost be harder because I have to spend time faffing about deciding which image library to pull in for Go, or dealing with async for Rust. But once that is actually done, I just ship the binary and simply copy it somewhere to get it on the path, and I never have to worry about reading gradle/maven docs or anything like that.
So I'll finish by saying that my ideal build tool is probably not a great one. What it is crucially is a simple one. I think that's that gap right now, that Java has these huge, immensely powerful and general build tools, build tools that I am guessing eventually gain equivalents in the Rust and Go worlds when projects grow old and gnarly enough to require a bunch of custom build stuff, but it doesn't have baby's first build tool like go build and cargo, where you can just get an idea and start building and come out the other side with an artifact and 0 time spent on thinking about the build system, until you actually need the kind of complexity that maven and gradle provide. Give me a build tool that assumes the standard src/ and test/ directory layout, then builds everything into some sort of archive file, creates a minimized JRE to run it, accepts an argument for an aot.cache file location, or for the more difficult option runs the program to generate that file and then bundles it up with the archive, bundles all the libraries that I've pulled into the project up into the archive along with all the resources declared for the project as well, and then spits out a single file artifact that I can immediately use and run. Give me a build tool that I don't even realize is there until I actually need that complexity.
I understand if this is vague and not a great answer, and I also appreciate all the work you've done for the Java community, so thanks for replying.
Comment by mike_hearn 3 hours ago
Native Image does produce single binaries in many cases, but what we need here is a much better tool in general. Actually I'm working on one right now, although it's not JVM specific. Want to take a look?
Comment by tadfisher 1 day ago
Comment by ptx 1 day ago
Comment by samus 8 hours ago
Comment by jgon 1 day ago
I’m sure that all of this stuff can be strung together after spending a suitable amount of time trolling through the documentation of the individual tools, but it’s far cry from go build and cargo build, and I think it would be great if Java could narrow the gap in this aspect.
Comment by samus 1 day ago
Comment by treyd 1 day ago
Comment by Skinney 1 day ago
Comment by harlan_pdx 1 day ago
Comment by cyberax 1 day ago
It's a shame that Sun/Oracle never partnered with them to bring native apps. This could have saved Java on the desktop.
Comment by wahern 1 day ago
I don't remember if GCJ supported loading and running code dynamically with a built-in JIT or interpreter. I think it was just pure AOT, which caused some compatibility headaches.
Comment by atgreen 1 day ago
Comment by java-man 1 day ago
I wish we had GCJ resurrected, now that the java libraries are GPL'd.
Comment by alex7o 1 day ago
Comment by cyberax 1 day ago
Its biggest downside was the use of Boehm GC that had some issues with large heaps.
Comment by pjmlp 1 day ago
The big difference until GraalVM and OpenJ9 became available as open source, was that all those vendors made AOT compilation a commercial feature, and thus most devs never cared they existed.
In fact GraalVM was one of the main reasons Excelsior JET eventually closed doors.
Comment by misja111 1 day ago
Comment by pjmlp 5 hours ago
Comment by patwolf 1 day ago
Comment by samus 1 day ago
Comment by pjmlp 5 hours ago
Comment by DonHopkins 1 day ago
Comment by pjmlp 1 day ago
Comment by hn_submit 1 day ago
Comment by pjmlp 5 hours ago
Java is an ecosystem like C and C++, there were always multiple implementations to choose from, some of them required money for the goodies like AOT.
Comment by java-man 1 day ago
Comment by layer8 1 day ago
Therefore I don’t see AOT-only becoming an integral part of standard Java in the foreseeable future.
Comment by jasomill 1 day ago
Existing code bases can be a pain, though, especially applications that heavily rely on things like C++/CLI and COM Interop that basically need to be rewritten from scratch.
Which is not to say that it's intended to replace the traditional JIT runtime in applications where it isn't troublesome, because it's not.
Comment by layer8 1 day ago
Yes, and that’s a significant limitation in the Java library and framework ecosystem.
Comment by Rohansi 1 day ago
Comment by pjmlp 5 hours ago
Comment by java-man 1 day ago
i guess what i am saying is that AOT-only case is not "standard java", but something that will make a (more) useful replacement for things like c/c++.
Comment by samus 1 day ago
What is the objective here? Startup latency or throughput? Both will be vastly improved by JEP 544.
Comment by nirvdrum 1 day ago
[1] -- https://www.graalvm.org/latest/reference-manual/native-image... [2] -- https://github.com/oracle/graal/issues/11327
Comment by Twirrim 1 day ago
There's a reason why folks keep coming back to JIT compilation. It's hard to beat the value that can be gained from actually gathering data on how the code is actually used, which leads to a whole set of potential optimisations (which is the problem Profile Guided Optimisation attempts to solve for AOT compiled code.) The JVM is arguably one of the most advanced and capable JITing runtimes.
As with anything it's a trade off. Fast start times, pretty fast running (I think maybe less memory usage?); vs the full JIT speed you can get on the JVM at the cost of start-up speed and memory consumption. All depends on what you want to use the application for.
If you're talking something like a serverless function, go native. If you're talking production server where you're measuring runtime in more than dozens of minutes, probably better to stick to the JVM & JIT.
Comment by bebop 1 day ago
Comment by pjmlp 1 day ago
Comment by exabrial 1 day ago
Comment by samus 1 day ago
Comment by za3faran 23 hours ago
Comment by invalidname 1 day ago
Comment by stevefan1999 1 day ago
Comment by pjmlp 1 day ago
Comment by jayd16 23 hours ago
I'm not sure the pissing contest is really relevant, nor do I think Excelsior JET is all that common but if that is a similar system and you would like to talk about the real world impact please expand on it.
https://learn.microsoft.com/en-us/dotnet/core/deploying/read...
Comment by pjmlp 8 hours ago
Excelsior JET wasn't the only commercial vendor, only one example, there were others, two surviving ones are PTC and Aicas, meanwhile IBM open sourced Websphere Real Time JVM AOT as part of Open J9.
A big difference between .NET and Java world, is that since early days Sun licensed the technology, thus the ecosystem is like C and C++, with plenty of options to choose from, each with its own set of JIT, AOT and GC flavours.
Even Android, while not being Java, has had JIT cache + AOT since Android 7, after trying to be pure AOT on Android 5, when Dalvik was replaced by ART.
.NET has had NGEN since day one, however it has been rather basic in optimizations, designed for quick startup of Windows Forms applications and little else.
Sing# and System C# were quite interesting, but they never left Microsoft Research into regular .NET.
Mono was the one caring about proper AOT compilation and JIT caches, then .NET Native was created by the Windows team which was more interested into using COM to replace what was left of .NET on Windows since Longhorn than anything else.
Java and .NET only started caring about offering free beer AOT compilation, JIT caches, due to return of AOT compiled languages and the adoption competition in the server room from those languages.
Ideally, they should have supported proper AOT compilation, and value types (in Java's case) since day one, given languages like Oberon, Modula-3 or Eiffel, that predated them.
Instead, both platforms are now catching up with those 1990's languages.
Comment by ledo9915 1 day ago
Comment by xxs 1 day ago
Lots of the strautup time is class resolution/loading. With that being said - some time last year I ended up optimizing on the main application servers developers run with startup time being over 90s (and often times close to 3min), down to 11seconds (still tons of access of database configurations, secrets, discoveries, and what not). One of the main optimizations was runtime build up of a single jar with the classes being loaded, and then concurrently verifying the classes/resources have not changed.
Comment by samus 1 day ago
Comment by SillyUsername 1 day ago
I suppose write once run anywhere is no longer a goal either.
"It is not a goal to support all CPU architectures currently supported by HotSpot."
This pretty much validates the point of view that VM design is now baggage, as a sandbox it has been flawed, for performance it's been prohibitive, and cross platform portability by virtue of being virtual, was just a convenient byproduct.
AI now handles the portability, sandbox security hasn't changed (cf. docker still has sandbox problems, LLMs have sandbox problems, it's always an ongoing concern) and that just leaves Java, as always, chasing performance.
Comment by randomUUID 1 day ago
- "Improve startup and warmup time by making optimized native code for an application instantly available when the HotSpot Java Virtual Machine starts."
- "If the workload changes in production, regenerate native code dynamically for continued peak performance, providing the best of both ahead-of-time (AOT) and just-in-time (JIT) compilation."
- "Ensure that shifting from AOT-compiled code to JIT-compiled code is invisible to applications."
That is JEP544 doesn't substitute JVM and JIT optimizations. It just changes the nature of the JIT's outcome.
Comment by nirvdrum 1 day ago
Comment by pjmlp 1 day ago