The GraalVM Dashboard is a web-based tool that visualizes the composition of a native executable. It displays the breakdown of packages, classes, and methods included in a native executable, and provides a visual summary of objects that contributed most to its heap size. The GraalVM Dashboard uses report files created by the native image builder. (For more information, see GraalVM Getting Started.)
This guide demonstrates how to use the dashboard to optimize the size of a native executable. It introduces two implementations of a “fortune” sample application that simulate the traditional fortune
Unix program (for more information, see fortune).
Note: This guide assumes you have installed Maven.
Package the contents of the first implementation (fortune) as a native executable and review its composition.
Make sure you have installed a GraalVM JDK. The easiest way to get started is with SDKMAN!. For other installation options, visit the Downloads section.
git clone https://github.com/graalvm/graalvm-demos
cd fortune-demo/fortune
mvn clean package
mvn -Pnative -Dagent exec:exec@java-agent
The application will return a random saying.
The agent generates the configuration files in the target/native/agent-output
subdirectory.
mvn -Pnative -Dagent package
When the command completes, a native executable, fortune
, is generated in the /target
directory of the project and ready for use.
./target/fortune
The application should slowly print a random phrase.
The application’s pom.xml file employs the Native Image Maven plugin to build a native executable, configured to produce diagnostic data using these two options:
-H:DashboardDump=fortune -H:+DashboardAll
These options result in a file named fortune.bgv. (For more information about different options, see Dumping the Data for GraalVM Dashboard.)
Compare the sizes of the JAR file and the native executable (for example, using du
):
du -sh target/*
0B target/archive-tmp
136K target/classes
17M target/fortune
2.0M target/fortune-1.0-jar-with-dependencies.jar
32K target/fortune-1.0.jar
44M target/fortune.bgv
4.0K target/fortune.build_artifacts.txt
0B target/generated-sources
4.0K target/maven-archiver
8.0K target/maven-status
0B target/test-classes
The size of the JAR file is 2MB, compared to the 17MB size of the native executable. The increase in size is because the native executable contains all necessary runtime code as well as pre-initialized data in its heap.
Open the GraalVM Dashboard and load the fortune.bgv file. (Click +, click Select File, select the fortune.bgv file from the target directory, and then click OK.)
The GraalVM dashboard provides two visualizations of a native executable: code size breakdown and heap size breakdown. (For more information, see Code Size Breakdown and Heap Size Breakdown, respectively.)
The screenshot above visualizes the code breakdown of the fortune
native executable, a great part of which consists of the Jackson JSON parser library implemented in the package com.fasterxml
. One approach to reduce the size of a native executable is to minimize the amount of space taken by code. The code size breakdown gives you an insight into the amount of space taken up by the packages that are included in your native executable.
Furthermore, the screenshot below shows that the heap of the native executable contains 4MB of Bytes and almost 800KB of Strings. Another approach to reduce the size of a native executable is to minimize the size of its heap.
In the next section, we’ll consider an alternative implementation for the fortune
application that reduces the amount of code and reduces the size of the heap.
The first implementation of the fortune application uses the Jackson JSON parser (package com.fasterxml
) at runtime to parse the contents of a resource file that the native image builder has included in the native executable. An alternative implementation (named “staticfortune”) parses the contents of the resource file at build time. This means that the resource file is no longer included in the executable, and the code required to parse the file is omitted from the native executable because it is only required at build time.
cd ../staticfortune
mvn clean package
mvn -Pnative -Dagent exec:exec@java-agent
The application will print a random saying. The agent generates the configuration files in the target/native/agent-output
subdirectory.
mvn -Pnative -Dagent package
When the command completes, a native executable, staticfortune
, is generated in the /target
directory of the project and ready for use.
./target/staticfortune
The application should behave in exactly the same way as the first implementation.
The application’s pom.xml file again uses the Native Image Maven plugin to build a native executable. However, for this implementation it adds an extra option to initialize class demo.StaticFortune
at build time:
-H:DashboardDump=staticfortune -H:+DashboardAll --initialize-at-build-time=demo.StaticFortune
Compare the sizes of the JAR file and the native executable:
du -sh target/*
0B target/archive-tmp
76K target/classes
0B target/generated-sources
4.0K target/maven-archiver
4.0K target/maven-status
4.3M target/staticfortune
2.0M target/staticfortune-1.0-jar-with-dependencies.jar
32K target/staticfortune-1.0.jar
9.0M target/staticfortune.bgv
4.0K target/staticfortune.build_artifacts.txt
0B target/test-classes
The size of the native executable has reduced in size from 17MB to 4.3MB.
The reduction in size is due to the use of the --initialize-at-build-time=
argument used with the Native Image Maven plugin.
The build created a file named staticfortune.bgv. Load it into the GraalVM Dashboard to view the composition of the staticfortune
native executable.
The screenshot above demonstrates that the code in the com.fasterxml
package is no longer present. There are also reductions in the amount of code included from the java.util
, java.math
, and java.text
packages.
The screenshot below illustrates that there has also been a significant reduction in the amount of heap given to Strings (767KB versus 184KB), and a reduction in Bytes from 4MB to 862KB.