The GraalVM Native Image Ahead-of-Time (AOT) compiler for Java creates native executables that start much faster, use less CPU and memory, are more secure, and have a smaller disk size than traditional Java applications with a Just-in-Time (JIT) compiler. With Oracle GraalVM for Java 17 and 20, Oracle killed the ‘Enterprise Edition’ brand and made its performance-boosting features free for production use for a limited time under a new permissive license. That pushes native Java executables closer to the speed of Java applications with a JIT compiler. GraalVM will simultaneously release with new Java versions, supporting the current Java and LTS versions, and the previous LTS version for one additional year.
The first two performance boosters copy Just-in-Time Java features: the G1 garbage collector and compressed object headers and pointers. The third one adapts a Just-in-Time Java feature: Profile-Guided Optimizations (PGO) collect profiling information at runtime. But unlike the JIT compiler, GraalVM Native Image uses this profiling data at build time for application-specific optimizations, not at runtime.
The new GraalVM Free Terms and Conditions (GFTC) license makes these former Enterprise Editions free for production use. But that's "free as in free beer" – it's not an open-source license. On the other hand, the GraalVM Community Edition (CE) is still available under the open-source GNU General Public License (GPL). But the CE lacks these three closed-source performance boosters. Further details may be found at the Oracle FAQ page.
Oracle benchmarked Native Image with G1 and PGO against the HotSpot C2 JIT compiler in the Spring PetClinic sample application on Java 20. Native Image started in 0.22 seconds, just 3% of HotSpot's 7.18 seconds. Memory usage measured with the Resident Set Size (RSS) was 694 MB – 40% of HotSpot's 1,751 MB. But in peak throughput, Native Image still trailed the JIT compiler with 10,249 requests/s, 80% of the 12,800 requests/s HotSpot achieved. Still, Oracle says, "In many cases, we see AOT even ahead of JIT for peak throughput."
Combining memory usage and requests/s, Native Image reached 14,780 requests/GB/s, twice HotSpot's 7,310 requests/GB/s. Oracle pointed out that this improved efficiency can save cloud costs. Running more requests may require more CPU power if processing these requests is CPU-constrained.
Java Language Architect Mark Reinhold identified the "long-term pain points of Java's slow startup time, slow time-to-peak performance, and large footprint" when defining the goal for project Leyden in April 2020. Native Image solves these pain points. But using GraalVM Native Image comes at the price of some possibly showstopping constraints and a more expensive troubleshooting process. The OpenJDK project Coordinated Restore at Checkpoint (CRaC) only solves startup time and slow time-to-peak performance but comes with fewer constraints.
The GraalVM team recommends using an application framework with Native Image. Helidon, Micronaut, Quarkus, and Spring Boot (since version 3.0 from November 2022) support GraalVM in production. The official GraalVM Community Survey 2022 showed that Spring Boot is the most popular, with 49% usage among respondents, up from 34% last year. "No framework" came in second at 26%. Quarkus placed third at 19%, up slightly from 18% year-over-year. "Other" was fourth at 15%, down from 25% the year before. And Micronaut was fifth at 14% versus 12% in 2021.
The GraalVM project is part of Oracle Labs. Apart from Native Image, it also contains the Graal JIT compiler, written in Java. The Graal JIT compiler now includes the ZGC garbage collector. Oracle announced last year that these two Java compilers would join OpenJDK. Back then, the GraalVM Enterprise Edition was not expected to move there.
The other GraalVM projects did not move: The Truffle framework for running languages like JavaScript or Python on GraalVM; and Java on Truffle, a Java replacement for the entire Hotspot VM. They received new features in this GraalVM release.
Native Image was improved with various slight speed boosts in this release, including machine learning for better branch prediction. The Native Image developer experience has also improved with: reduced build process memory footprint, automatic build environment setup in Windows, more user-friendly error handling, and reports with build details. Native Image can now also create a Software Build of Materials (SBOM).
Native Image enabled remote management over JMX as an experimental feature in this release and added three new JDK Flight Recorder (JFR) events. AWT now works in Native Image on Linux. That leaves macOS as the last platform without support for Java desktop applications.
Native Image Bundles are new and enable reproducible builds. Alongside the native executable, such bundles contain a JAR file of the application and the necessary build information. The GraalVM JDK also now includes Native Image by default and has stable download URLs, easing life for container image authors and CI/CD systems.
Alina Yurenko, developer advocate for GraalVM at Oracle Labs, was happy to answer some questions for InfoQ.
InfoQ: This is the first GraalVM release after the GraalVM Java compilers started their move to OpenJDK. How has that move been going so far?
Alina Yurenko: At JavaOne 2022, we announced our plans to contribute the most applicable portions of the GraalVM just-in-time (JIT) compiler and Native Image technology to OpenJDK. A few months ago, we announced Project Galahad, where this work will begin. However, for GraalVM users, the first tangible result of this effort is aligning the GraalVM release schedule with OpenJDK's schedule.
InfoQ: The initial announcement (see the last question) didn't suggest any changes for the GraalVM Enterprise Edition. Now many of its EE features, such as PGO and G1, are available for free under a new license. What prompted this change?
Yurenko: The initial announcement and subsequent communications did talk about the alignment with OpenJDK: "The plan is to align all the GraalVM technologies with Java both from a release perspective and from a licensing perspective." Having GraalVM releases that support the latest Oracle-designated LTS release under a free license is a crucial part of the alignment.
InfoQ: The distribution is now called "Oracle GraalVM". What do you know about the plans of other organizations to ship GraalVM distributions? We have many OpenJDK distributions, after all.
Yurenko: There are many GraalVM distributions as well. Oracle provides the GraalVM Community Edition under an open-source license. And third parties such as Gluon, Red Hat, and Bellsoft provide their forks of GraalVM CE-based code. We would not be surprised to see further distributions become available over time.
InfoQ: Why and when should Java developers consider using the Graal JIT compiler over the standard Hotspot JIT compiler?
Yurenko: Here are some areas where developers and applications may see benefits:
- Partial escape analysis. Removes unnecessary object allocations by performing scalar replacement in branches where the object does not escape and ensuring that the object exists in the heap in branches where it must escape. This reduces both the memory footprint of the application and the CPU load incurred by GC. The impact of this optimization is even larger for more modern Java code that uses lambdas or otherwise allocates many short-lived objects.
- Auto-vectorization. GraalVM can automatically recognize various loop structures and perform automatic vectorization to provide additional performance benefits where possible.
These advantages and resulting performance benefits have, for example, been observed by researchers working on the Renaissance benchmark suite, the Facebook engineering team, and Ionut Balosin and Florin Blanaru in their "JVM Performance Comparison for JDK 17" article.
Any Java developer using the default JIT compiler should consider giving the Graal compiler a try and measure how much it improves the performance of their workloads. Generally, predicting how much performance users can gain from switching to Graal is challenging, as every workload is different and has different performance profiles and goals.
InfoQ: A Native Image practitioner recommended using Java with a JIT compiler during development last year. He said using Native Image on developer machines and debugging native Java executables should be the exception. What are your recommendations on using GraalVM Native Image during development today?
Yurenko: Using Java with a JIT compiler during development is correct: use it to debug your core program logic – and debug early. Fast debug/test cycles are one of the strengths of the Java ecosystem. Most developers spend most of their development time here.
However, once your basic logic works and you want to debug and test in more production-like conditions with a broader set of tests, you might want to try Native Image. You probably need to test in the cloud rather than using mocked versions of cloud services then. You aren't going to notice the difference in Java programs with Native Image except under more production-like conditions anyway.
Where the Native Image build fits into your development process depends on the likelihood of encountering problems with building a native image. Suppose you use a framework like Spring Boot 3 or Micronaut with library dependencies known to work with Native Image. In that case, you probably can do the Native Image build late in your development cycle and only in your CI/CD pipeline since Native Image builds won't create or reveal more problems. Testing with Native Image then helps you understand how your program works at scale or in cloud conditions. But if you use older libraries that require the native image tracing agent to handle dynamic Java features like reflection, you do more native image builds on developer machines to debug configuration problems with native executables. Then you will use Native Build Tools and native debugging.
InfoQ: How do you define success for the GraalVM project? And how do you measure it?
Yurenko: The GraalVM project was created to provide a universal language runtime that can be embedded in any environment in various modes and that leverages the strengths of the Java ecosystem. Much of the initial research focused on demonstrating that we can run multiple programming languages with comparable efficiency to the single-language runtimes (see our work on R, Ruby and Java). We also demonstrated that we could embed GraalVM into various environments, from mobile devices to databases. The goal of Native Image is to marry the best of traditional Java with the benefits of native code, such as lower startup and footprint, and more predictable behavior.
As we have deployed GraalVM technologies into production in the past five years, the first step was the Hippocratic oath of system software — do no harm (tolerate no regression). Initially, we focused on the headline benchmarks of peak throughput. More recently, we've worked on other metrics, like memory footprint for both the runtime and compiler, build times, debuggability, and observability. We've also worked on the high level of interoperability that the Java ecosystem expects.
We've made tremendous progress over the last decade. Graal features are ready to be used in production. Native image build times have come down a lot and are reasonable for most projects. Startup time for our JIT compiler and peak throughput for native image-compiled binaries are better for many workloads. Plus, Oracle GraalVM (the former EE) is now free for production use.
Most importantly, GraalVM is now getting broad ecosystem support from other framework vendors. All major Java microservices frameworks, such as Spring Boot, Micronaut, Quarkus and Helidon, offer first-class support for GraalVM Native Image and the most popular cloud providers. More than 150 libraries and frameworks have adopted Native Image. 1,300 projects use GraalVM's GitHub action on GitHub alone, and you can also find a list of 30+ language implementations built on top of GraalVM's Truffle framework.
So, we certainly can claim excellent success for the project so far. Meanwhile, the Oracle Labs team is using the experience of GraalVM on various cloud development and deployment features. Be sure to follow our social media to keep updated on any announcements.
InfoQ: The GraalVM team gets feedback from many sources and could work in many areas – the Java compilers, the Truffle framework and its languages, the developer experience, compatibility with libraries and frameworks, etc. How does the team analyze feedback and prioritize work, especially now that it's part of OpenJDK?
Yurenko: Oracle looks at feedback related to GraalVM through the lens of research and product. Our engineering team is directly engaged with the community on social media, involved in our GitHub repos, working on new PRs, resolving issues, and reviewing community contributions. We aim to reduce developer pain points where most developers are affected and add new technologies with the most impact. Of course, as a commercial Oracle product, we also have to meet our customers' expectations for our regular support terms and conditions.
Embedded JavaScript in the JVM and other environments, like the Oracle Database and NetSuite, is also getting much attention. We continue to track improvements in both Java and JavaScript standards and the increasing use of WASM in JavaScript programs. GraalPy is also one of our priorities, and it was exciting that we were recently able to pass the PyTorch test suite with the JVM. We are getting optimistic that GraalPy will be a reasonable choice for Python developers doing data science in the next year. Embedded use cases are also on our radar: Oracle will invest in embedding GraalVM in more products shortly, and third parties like Enso are doing so as well. Beyond all those sensible product-oriented directions, Oracle Labs will continue to use GraalVM as the basis for research projects that are much further out there, and we expect only to gain momentum there.
The GraalVM home page provides more information on the Java compilers and the other GraalVM projects. GraalVM for Java 21 will release simultaneously with Java 21 on September 19, 2023, ending support for Java 20. The last GraalVM release for Java 17 is planned for October 24, 2023. GraalVM intends to ship simultaneously with the next non-LTS Java version 22 on March 19, 2024.