Skip to content

Commit 05ebc3b

Browse files
committed
[GR-53621] Extend Specify Class Initialization Explicitly guide with a demo part.
PullRequest: graal/18008
2 parents 3de39db + 2bfaf55 commit 05ebc3b

File tree

2 files changed

+164
-15
lines changed

2 files changed

+164
-15
lines changed

docs/reference-manual/native-image/ClassInitialization.md

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,11 @@ However, Java class initialization semantics impose several constraints that com
2323
* When a class is initialized, all its superclasses and superinterfaces with default methods must also be initialized.
2424
Interfaces without default methods, however, are not initialized.
2525
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.
26-
2726
* Relevant supertypes of types initialized at build time must also be initialized at build time.
2827
* Relevant subtypes of types initialized at runtime must also be initialized at runtime.
2928
* No instances of classes that are initialized at runtime must be present in the executable.
3029

3130
To enjoy the complete out-of-the-box experience of Native Image and still get the benefits of build-time initialization, Native Image does two things:
32-
3331
* [Build-Time Initialization](#build-time-initialization)
3432
* [Automatic Initialization of Safe Classes](#automatic-initialization-of-safe-classes)
3533

@@ -43,7 +41,6 @@ Native Image initializes most JDK classes at build time, including the garbage c
4341
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.
4442
If you discover an issue with a JDK class behaving incorrectly because of class initialization at build time, please [report an issue](https://github.com/oracle/graal/issues/new).
4543

46-
4744
## Automatic Initialization of Safe Classes
4845

4946
For application classes, Native Image tries to find classes that can be safely initialized at build time.
@@ -54,10 +51,9 @@ A method is considered unsafe if:
5451
* 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.
5552
* It calls a method that cannot be reduced to a single target (a virtual method).
5653
This restriction avoids the explosion of search space for the safety analysis of static initializers.
57-
* 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.
54+
* It is substituted by Native Image. Running initializers of substituted methods would yield different results in the hosting Java Virtual Machine (JVM) than in the produced executable.
5855
As a result, the safety analysis would consider some methods safe but calling them would lead to illegal states.
5956

60-
A test that shows examples of classes that are proven safe can be found [here](https://github.com/oracle/graal/blob/master/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/clinit/TestClassInitializationMustBeSafeEarly.java).
6157
The list of all classes that are proven safe is output to a file via the `-H:+PrintClassInitialization` command-line option to the `native-image` tool.
6258

6359
> Note: You can also [Specify Class Initialization Explicitly](guides/specify-class-initialization.md).
Lines changed: 163 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,183 @@
11
---
22
layout: ni-docs
33
toc_group: how-to-guides
4-
link_title: Specify Class Initialization
4+
link_title: Specify Class Initialization Explicitly
55
permalink: /reference-manual/native-image/guides/specify-class-initialization/
66
---
77

88
# Specify Class Initialization Explicitly
99

10-
Two command line flags explicitly specify when a class should be initialized: `--initialize-at-build-time` and `--initialize-at-run-time`.
11-
You can use the flags to specify whole packages or individual classes.
12-
For example, if you have the classes `p.C1`, `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 to `native-image` on the command line:
10+
By default, Native Image initializes application classes at runtime, except for the classes that Native Image proves "safe" for initialization at build time.
11+
However, you can influence the default behavior by explicitly specifying the classes to be initialized at build-time or runtime.
12+
For that, there are two command-line options: `--initialize-at-build-time` and `--initialize-at-run-time`.
13+
You can use these options to specify whole packages or individual classes.
14+
For example, if you have the classes `p.C1`, `p.C2`, … ,`p.Cn`, you can specify that all the classes in the package `p` are to be initialized at build time by passing the following option to `native-image`:
1315
```shell
1416
--initialize-at-build-time=p
1517
```
16-
17-
If you want only one of the classes in package `p` to be initialized at runtime, use:
18+
If you want only class `C1` in package `p` to be initialized at runtime, use:
1819
```shell
1920
--initialize-at-run-time=p.C1
2021
```
2122

22-
The whole class hierarchy can be initialized at build time by passing `--initialize-at-build-time` on the command line.
23+
You can also programmatically specify class initialization using the [`RuntimeClassInitialization`] class (https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/RuntimeClassInitialization.java) from the [Native Image Feature interface](https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/Feature.java).
24+
25+
This guide demonstrates how to build a native executable by running the class initializer at runtime (default behavior), and then at build time, and compares the two approaches.
26+
27+
### Prerequisite
28+
Make sure you have installed a GraalVM JDK.
29+
The easiest way to get started is with [SDKMAN!](https://sdkman.io/jdks#graal).
30+
For other installation options, visit the [Downloads](https://www.graalvm.org/downloads/) section.
31+
32+
## Run a Demo
33+
34+
For the demo, run a simple Java application that parses some Java talks from 2023.
35+
The parser creates records and adds them to a `List<Talk>` collection.
36+
37+
1. Save the following Java source code in a file named _TalkParser.java_:
38+
```java
39+
import java.util.ArrayList;
40+
import java.util.List;
41+
import java.util.Scanner;
42+
43+
public class TalkParser {
44+
private static final List<Talk> TALKS = new ArrayList<>();
45+
static {
46+
Scanner s = new Scanner("""
47+
Asynchronous Programming in Java: Options to Choose from by Venkat Subramaniam
48+
Anatomy of a Spring Boot App with Clean Architecture by Steve Pember
49+
Java in the Cloud with GraalVM by Alina Yurenko
50+
Bootiful Spring Boot 3 by Josh Long
51+
""");
52+
while (s.hasNextLine()) {
53+
TALKS.add(new Talk(s.nextLine()));
54+
}
55+
s.close();
56+
}
57+
58+
public static void main(String[] args) {
59+
System.out.println("Talks loaded using scanner:");
60+
for (Talk talk : TALKS) {
61+
System.out.println("- " + talk.name());
62+
}
63+
}
64+
}
65+
66+
record Talk (String name) {}
67+
```
68+
69+
2. Compile the application:
70+
```bash
71+
javac TalkParser.java
72+
```
73+
74+
3. Build a native executable, explicitly running the class initializer at runtime:
75+
```bash
76+
native-image --initialize-at-run-time=TalkParser,Talk -o runtime-parser TalkParser
77+
```
78+
You can omit the `--initialize-at-run-time=TalkParser,Talk` option in this example because these classes are marked for initialization at run time by default.
79+
The `-o` option specifies the name of the output file.
80+
81+
4. Run and `time` the native application:
82+
```bash
83+
time ./runtime-parser
84+
```
85+
On a machine with 16 GB of memory and 8 cores, you should see a result similar to:
86+
```
87+
Talks loaded using scanner:
88+
- Asynchronous Programming in Java: Options to Choose from by Venkat Subramaniam
89+
- Anatomy of a Spring Boot App with Clean Architecture by Steve Pember
90+
- Java in the Cloud with GraalVM by Alina Yurenko
91+
- Bootiful Spring Boot 3 by Josh Long
92+
./runtime-parser 0.00s user 0.00s system 52% cpu 0.010 total
93+
```
94+
The application parses the text block at runtime.
95+
96+
Check the file size which should be around 13M:
97+
```
98+
du -sh runtime-parser
99+
```
100+
101+
5. Next, build a native executable initializing `TalkParser` at build time, and providing a different name for the output file to differentiate it from the previous build. The `Talk` record has to be initialized explicitly too, so the objects of this type will be persisted in the executable heap.
102+
```bash
103+
native-image --initialize-at-build-time=TalkParser,Talk -o buildtime-parser TalkParser
104+
```
105+
106+
If your application adds additional types to the executable heap, each type (or the corresponding package) needs to be marked for build-time initialization explicitly to fulfill the requirements of `--strict-image-heap`.
107+
An appropriate actionable error message will guide you through the process.
108+
109+
6. Run and `time` the second executable for comparison:
110+
```bash
111+
time ./buildtime-parser
112+
```
113+
This time you should see something similar to this:
114+
```
115+
Talks loaded using scanner:
116+
- Asynchronous Programming in Java: Options to Choose from by Venkat Subramaniam
117+
- Anatomy of a Spring Boot App with Clean Architecture by Steve Pember
118+
- Java in the Cloud with GraalVM by Alina Yurenko
119+
- Bootiful Spring Boot 3 by Josh Long
120+
./buildtime-parser 0.00s user 0.00s system 53% cpu 0.016 total
121+
```
122+
Check the file size which should decrease to around 6.4M!
123+
```
124+
du -sh buildtime-parser
125+
```
126+
The file size change is because Native Image runs the static initializer at build time, parsing the text block, and persisting only the `Talk` records in the executable.
127+
As a result, the majority of the scanning infrastructure does not become reachable when Native Image statically analyzes the application and is, therefore, not included in the executable.
128+
129+
Another valuable criterion for profiling applications more accurately is the number of instructions, which can be obtained using the [Linux `perf` profiler](../PerfProfiling.md).
130+
131+
For example, for this demo application, the number of instructions decreased by almost 30% (from 11.8M to 8.6M) in the case of build-time class initialization:
132+
```bash
133+
perf stat ./runtime-parser
134+
Talks loaded using scanner:
135+
- Asynchronous Programming in Java: Options to Choose from by Venkat Subramaniam
136+
(...)
137+
Performance counter stats for './runtime-parser':
138+
(...)
139+
11,323,415 cycles # 3.252 GHz
140+
11,781,338 instructions # 1.04 insn per cycle
141+
2,264,670 branches # 650.307 M/sec
142+
28,583 branch-misses # 1.26% of all branches
143+
(...)
144+
0.003817438 seconds time elapsed
145+
0.000000000 seconds user
146+
0.003878000 seconds sys
147+
```
148+
```bash
149+
perf stat ./buildtime-parser
150+
Talks loaded using scanner:
151+
- Asynchronous Programming in Java: Options to Choose from by Venkat Subramaniam
152+
(...)
153+
Performance counter stats for './buildtime-parser':
154+
(...)
155+
9,534,318 cycles # 3.870 GHz
156+
8,609,249 instructions # 0.90 insn per cycle
157+
1,640,540 branches # 665.818 M/sec
158+
23,490 branch-misses # 1.43% of all branches
159+
(...)
160+
0.003119519 seconds time elapsed
161+
0.001113000 seconds user
162+
0.002226000 seconds sys
163+
```
164+
165+
This demonstrates how Native Image can shift work from runtime to build time: when the class is initialized at build time, the text block is parsed when the executable is being built and only the parsed objects are included.
166+
This not only makes the executable smaller in file size, but also faster to run: when the executable runs, the `Talk` records already exist and only need to be printed.
167+
168+
To ensure native executables built with Native Image are as compatible as possible with the HotSpot behavior, application classes that cannot be safely initialized at build time, are initialized at runtime.
169+
You as a user, or a framework that you use, must explicitly request build-time initialization for certain classes to benefit from smaller file sizes and faster times to run.
170+
Include the right data structures to avoid the image size blowing up instead.
171+
We also recommend using `--initialize-at-build-time` with single classes only.
172+
It may be that you need to add a lot of `--initialize-at-build-time` entries.
173+
Note that incorrect build-time initialization can lead to problems that are to be avoided in production settings such as dysfunctional behavior or including sensitive data such as passwords or encryption keys.
174+
175+
### Conclusion
23176

24-
Class initialization can also be specified programmatically using [`RuntimeClassInitialization`](https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/RuntimeClassInitialization.java) from the [Native Image feature](https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/Feature.java).
177+
This guide demonstrated how you can influence the default `native-image` class initialization policy, and configure it to initialize a specific class at build time, depending on the use case.
178+
The benefits of the build-time versus run-time initialization are described in [Class Initialization in Native Image](../ClassInitialization.md), but, in short, build-time initialization can significantly decrease the overall file size and improve the runtime of your application when used correctly.
25179

26180
### Related Documentation
27181

28182
* [Class Initialization](../ClassInitialization.md)
29-
* [Native Image Build Configuration](../BuildConfiguration.md)
30-
* [Use System Properties in a Native Executable](use-system-properties.md)
183+
* [Native Image Build Configuration](../BuildConfiguration.md)

0 commit comments

Comments
 (0)