- Dev Build
- Native Image
- Build Output
- Build Configuration
- Tracing Agent
- Experimental Agent Options
- Native Image Compatibility and Optimization Guide
- Class Initialization in Native Image
- Static Native Images
- Native Image Options
- Native Image Hosted and Runtime Options
- Native Image Inspection Tool
- Native Image C API
- Implementing Native Methods in Java with Native Image
- LLVM Backend for Native Image
- Debug Info Feature
- Points-to Analysis Reports
- Using System Properties in Native Image
- Profile-Guided Optimizations
- Memory Management at Image Run Time
- Generating Heap Dumps from Native Images
- JDK Flight Recorder with Native Image
- JCA Security Services on Native Image
- Dynamic Proxy on Native Image
- Java Native Interface (JNI) on Native Image
- Reflection on Native Image
- Accessing Resources in Native Images
- Logging on Native Image
- URL Protocols on Native Image
- Native Image ARM64 Support
- GraalVM Updater
- Languages References
- Embedding Reference
- Polyglot Programming
Class Initialization in Native Image
The semantics of Java requires that a class is initialized the first time it is accessed at runtime. Class initialization has negative consequences for compiling Java applications ahead-of-time for the following two reasons:
- It significantly degrades the performance of a native executable: every access to a class (via a field or method) requires a check to ensure the class is already initialized. Without optimization, this can reduce performance by more than twofold.
- It increases the amount of computation–and time–to startup an application. For example, the simple “Hello, World!” application requires more than 300 classes to be initialized.
To reduce the negative impact of class initialization, Native Image supports class initialization at build time: it can initialize classes when it builds an executable, making runtime initialization and checks unnecessary. All the static state from initialized classes is stored in the executable. Access to a class’s static fields that were initialized at build time is transparent to the application and works as if the class was initialized at runtime.
However, Java class initialization semantics impose several constraints that complicate class initialization policies, such as:
When a class is initialized, all its superclasses and superinterfaces with default methods must also be initialized. Interfaces without default methods, however, are not initialized. To accommodate this requirement, a short-term “relevant supertype” is used, as well as a “relevant subtype” for subtypes of classes and interfaces with default methods.
- Relevant supertypes of types initialized at build time must also be initialized at build time.
- Relevant subtypes of types initialized at runtime must also be initialized at runtime.
- No instances of classes that are initialized at runtime must be present in the executable.
To enjoy the complete out-of-the-box experience of Native Image and still get the benefits of build-time initialization, Native Image does three things:
- Build-Time Initialization of a Native Executable
- Automatic Initialization of Safe Classes
- Specifying Class Initialization Explicitly
To track which classes were initialized and why, pass the command line flag
-H:+PrintClassInitialization to the
This flag helps you configure the
native image builder to work as required.
The goal is to have as many classes as possible initialized at build time, yet keep the correct semantics of the application.
Build-Time Initialization of a Native Executable #
Native Image initializes most JDK classes at build time, including the garbage collector, important JDK classes, and the deoptimizer. For all of the classes that are initialized at build time, Native Image gives proper support so that the semantics remain consistent despite class initialization occurring at build time. If you discover an issue with a JDK class behaving incorrectly because of class initialization at build time, please report an issue.
Automatic Initialization of Safe Classes #
For application classes, Native Image tries to find classes that can be safely initialized at build time. A class is considered safe if all of its relevant supertypes are safe and if the class initializer does not call any unsafe methods or initialize other unsafe classes.
A method is considered unsafe if:
- It transitively calls into native code (such as
System.out.println): native code is not analyzed so Native Image cannot know if illegal actions are performed.
- It calls a method that cannot be reduced to a single target (a virtual method). This restriction avoids the explosion of search space for the safety analysis of static initializers.
- It is substituted by Native Image. Running initializers of substituted methods would yield different results in the hosting Java virtual machine (VM) than in the produced executable. As a result, the safety analysis would consider some methods safe but calling them would lead to illegal states.
A test that shows examples of classes that are proven safe can be found here.
The list of all classes that are proven safe is output to a file via the
-H:+PrintClassInitialization command line argument to the
Specifying Class Initialization Explicitly #
Two command line flags explicitly specify when a class should be initialized:
The flags specify whole packages or individual classes.
For example, if you have classes
p.C2, … ,
p.Cn, you can specify that all the classes in the package
p are initialized at build time by passing the following argument on the command line:
If you want one of the classes in package
p to be initialized at runtime, use:
The whole class hierarchy can be initialized at build time by passing
--initialize-at-build-time on the command line.
Class initialization can also be specified programmatically using
RuntimeClassInitialization from the Native Image feature.