GraalVM
GraalVM is a high-performance JDK distribution designed to accelerate the execution of applications written in Java and other JVM languages along with support for JavaScript, Ruby, Python, and a number of other popular languages.
GraalVM provides the native-image
tool to build native executables for Java apps. This is the primary tool for building native Java apps.
JIT vs. AOT
When building native images using GraalVM, an important concept to understand is AOT.
JIT
Bytecode is a intermediate representation, which needs to be translated to machine code for execution. JVM can simply interpret the bytecode and translate to machine code directly. However, this approach may be less performant in certain cases. A typical example is loops. The loop body may be executed many times.
Most JVM implementations use a technology called Just-in-time (JIT) compilation to improve the performance. The JIT compiler dynamically compiles bytecode into machine code and caches the result for later use. For the loop example, the bytecode of loop body can be compiled and cached. When executing the loop, the cached machine code can be reused to speed up the execution.
JIT compilation also incurs runtime cost. JIT compiler usually employees a complicated strategy to determine which part of bytecode should be compiled.
AOT
The term Ahead-of-time (AOT) compilation may have different meanings in different contexts. For GraalVM, AOT means compiling bytecode into native machine code at build-time. This allows Java programs to run as native executables.
GraalVM AOT compilation starts from the main
method of the main class. The executable includes the application classes, classes from third-party dependencies, classes from Java runtime libraries, and statically linked native code from JDK.
To enable AOT compilation, GraalVM runs an aggressive static analysis that requires a closed-world assumption. If this assumption doesn't hold, native image won't work as expected. When developing native images with GraalVM, the key point is to remove dynamic parts of an application.
Native Image
The native executable built by GraalVM doesn't run on the JVM, but includes necessary components from a runtime system called "Substrate VM". Substrate VM includes following components:
- Memory management - Garbage collectors
- Thread scheduling
- Java Native Interface (JNI) support
- Deoptimizer
Limitations
Due to the nature of AOT compilation, there are some limitations of GraalVM native image.
Some features require configurations.
- Dynamic class loading. Any class to be accessed by name at image run time must be enumerated at image build time.
- Reflection. Individual classes, methods, and fields that should be accessible via reflection need to be known ahead-of-time.
- Dynamic proxy. The list of interfaces that define dynamic proxies needs to be known at image build time.
- JNI. Any Java artifacts accessed by name via JNI must be specified during a native image generation.
- Serialization. Java serialization requires class metadata information in order to function and must be specified during a native image generation.
Some features are not compatible.
invokedynamic
bytecode and method handles.- Security manager.
Some features have different behavior.
- Signal handlers. No signal handlers are registered by default when building a native image, unless the
--install-exit-handlers
option is used. - Class initializers. Classes can be initialized at image build time.
- Finalizers. Finalizers are not invoked.
- Threads. Native Image does not implement long-deprecated methods in
java.lang.Thread
. - Unsafe memory access. Fields accessed using
sun.misc.Unsafe
need to be marked if classes are initialized at image build time. - Debugging and monitoring. JVMTI and other bytecode-based tools are not supported with Native Image. Debugging can only be done using native debuggers like GDB.
GraalVM and OpenJDK
Oracle is contributing GraalVM Community Edition Java code to OpenJDK to more closely align the development of the GraalVM technologies with that of Java. Oracle plans to contribute the most applicable portions of the GraalVM just-in-time (JIT) compiler and Native Image to the OpenJDK Community.