Skip to content

Commit 3cec7d0

Browse files
committed
[GR-54333] New guide: Optimize a Native Executable for File Size.
PullRequest: graal/18179
2 parents 02d7ccc + fa12fff commit 3cec7d0

File tree

2 files changed

+107
-0
lines changed

2 files changed

+107
-0
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,12 @@ Here you will learn how to:
2626
- [Create a Heap Dump from a Native Executable](create-heap-dump-from-native-executable.md)
2727
- [Debug Native Executables with GDB](debug-native-executables-with-gdb.md)
2828
- [Debug Native Executables with a Python Helper Script](debug-native-executables-with-python-helper.md)
29+
- [Embed an SBOM in a Native Executable to Identify Its Dependencies](use-sbom-support.md)
2930
- [Include Reachability Metadata Using the Native Image Gradle Plugin](include-reachability-metadata-gradle.md)
3031
- [Include Reachability Metadata Using the Native Image Maven Plugin](include-reachability-metadata-maven.md)
3132
- [Include Resources in a Native Executable](include-resources.md)
3233
- [Optimize a Native Executable with Profile-Guided Optimizations](optimize-native-executable-with-pgo.md)
34+
- [Optimize a Native Executable for File Size](optimize-file-size.md)
3335
- [Specify Class Initialization Explicitly](specify-class-initialization.md)
3436
- [Use Gradle to Build a Native Executable from a Java Application](https://graalvm.github.io/native-build-tools/latest/gradle-plugin-quickstart.html)
3537
- [Use Maven to Build a Native Executable from a Java Application](https://graalvm.github.io/native-build-tools/latest/maven-plugin-quickstart.html)
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
---
2+
layout: ni-docs
3+
toc_group: how-to-guides
4+
link_title: Optimize a Native Executable for File Size
5+
permalink: /reference-manual/native-image/guides/optimize-for-file-size/
6+
---
7+
8+
# Optimize a Native Executable for File Size
9+
10+
You can optimize your native executable by taking advantage of different optimization levels.
11+
This guide will demonstrate how to create small native executables for a given application, using the optimization for size, `-Os`.
12+
13+
> `-Os` enables `-O2` optimizations except those that can increase code or executable size significantly. Typically, it creates the smallest possible executables at the cost of reduced performance. Learn more in [Optimization Levels](../OptimizationsAndPerformance.md#optimization-levels).
14+
15+
### Prerequisite
16+
17+
Make sure you have installed Oracle GraalVM for JDK 23 or later.
18+
The easiest way to get started is with [SDKMAN!](https://sdkman.io/jdks#graal){:target="_blank"}.
19+
For other installation options, visit the [Downloads](https://www.graalvm.org/downloads/){:target="_blank"} section.
20+
21+
For the demo, run a "fortune teller" application that simulates the traditional `fortune` Unix program (for more information, see [fortune](https://en.wikipedia.org/wiki/Fortune_(Unix)){:target="_blank"}).
22+
23+
1. Clone the GraalVM Demos repository:
24+
```bash
25+
git clone https://github.com/graalvm/graalvm-demos.git
26+
```
27+
28+
2. Change directory to _fortune-demo/fortune-maven_:
29+
```bash
30+
cd fortune-demo/fortune-maven
31+
```
32+
33+
## Build a Native Executable with Default Configuration
34+
35+
1. Create a native executable using the [Maven plugin for Native Image](https://graalvm.github.io/native-build-tools/latest/maven-plugin.html){:target="_blank"}:
36+
```bash
37+
mvn -Pnative package
38+
```
39+
The command compiles the project, creates a JAR file with all dependencies, and then generates a native executable, `fortune`, in the _target_ directory.
40+
41+
2. (Optional) Run the application:
42+
```bash
43+
./target/fortune
44+
```
45+
The application will return a random saying.
46+
47+
3. Check the file size which should be around 13M:
48+
```bash
49+
du -h target/fortune
50+
```
51+
52+
## Build a Native Executable Optimized for Size
53+
54+
Next create a native executable with the size optimization on, giving a different name for the output file to differentiate it from the previous build.
55+
56+
1. Open the _pom.xml_ file. Find the `native-maven-plugin` declaration, and add the following build arguments within the `<configuration>` element. The configuration should look like this:
57+
```xml
58+
<configuration>
59+
<imageName>fortune-optimized</imageName>
60+
<buildArgs>
61+
<buildArg>-Os</buildArg>
62+
<buildArg>--emit build-report</buildArg>
63+
</buildArgs>
64+
</configuration>
65+
```
66+
The `-Os` option enables size optimization.
67+
The option `--emit build-report` generates a build report along with other artifacts in the _target_ directory.
68+
69+
2. Create the second native executable:
70+
```bash
71+
mvn -Pnative package
72+
```
73+
The command generates an executable file, `fortune-optimized`, in the _target_ directory.
74+
75+
3. Compare the sizes of all relevant output files:
76+
```bash
77+
du -h target/fortune*
78+
```
79+
You should see the output similar to this:
80+
```
81+
13M target/fortune
82+
16K target/fortune-1.0-SNAPSHOT.jar
83+
9.8M target/fortune-optimized
84+
1.9M target/fortune-optimized-build-report.html
85+
```
86+
The file size decreased from 13M to 9.8M!
87+
88+
How much the file size can be reduced by the `-Os` option varies between applications, and depends on how much Native Image applies inlining and other optimizations that increase size in the default `-O2` mode.
89+
90+
The build report generated in the previous step, _fortune-optimized-build-report.html_, tells exactly what was included in your native executable.
91+
It is an HTML file that you can open in a regular web browser.
92+
93+
In case your native executable is quite large in file size, you may want to review the list of embedded resources, the list of modules and packages included in the code area, or the list of object types in the image heap, and check whether these elements are essential for your application.
94+
Sometimes, large files are accidentally embedded as a resource due to erroneous regular expression patterns in the resource configuration of reachability metadata.
95+
Registering wrong or too many Java types for reflection can also increase the size of a native executable significantly, by making unnecessary parts of the application, libraries, or the JDK reachable by accident.
96+
Moreover, build-time initialization, if not used towards a specific goal, can cause large Java objects such as empty caches to be accidentally included in the image heap and, thus, cause bloat in a native executable.
97+
98+
Generally, it is a good idea to check file size, number of embedded resources, or other metrics from time to time, for example, when adding or updating dependencies, or even monitor build metrics frequently.
99+
For this, you can use the [machine-readable version of the build output](../overview/BuildOutput.md#machine-readable-build-output) or the [build reports for GitHub Actions](https://medium.com/graalvm/native-image-build-reports-and-update-notifications-351aca964a55){:target="_blank"}.
100+
101+
There are other Native Image techniques that can positively affect the executable size, besides improving other metrics, for example, [Profile-Guided Optimizations (PGO)](optimize-native-executable-with-pgo.md).
102+
103+
### Related Documentation
104+
105+
- [Optimizations and Performance](../OptimizationsAndPerformance.md)

0 commit comments

Comments
 (0)