This application demonstrates the use of isolates with GraalVM Native Image. The code implements a web service that renders plots of mathematical functions, such as sin(x). For each requested plot, the web service spawns an isolate, which is an independent execution context. The isolate generates the plot, and after it returns the result to the web service, it is discarded as a whole, along with any memory it used.
This demo uses Netty for the web server, the exp4j library to parse mathematical expressions, and JFreeSVG to generate SVG images.
The pom.xml specifies the expected dependencies to Netty, emp4j, and JFreeSVG. There is also the Maven plugin for GraalVM Native Image building to compile this Java application into a native executable.
-
Download and install the latest GraalVM JDK using SDKMAN!.
sdk install java 21.0.1-graal
-
Download or clone the repository and navigate into the
native-netty-plot
directory:git clone https://github.com/graalvm/graalvm-demos
cd graalvm-demos/native-netty-plot
For compilation, the native-image
depends on the local toolchain.
Please make sure that glibc-devel
, zlib-devel
(header files for the C library and zlib), and gcc
are available on your system. Some Linux distributions may additionally require libstdc++-static
.
See Prerequisites for Native Image.
The example is built with Maven:
mvn package
This creates a JAR file with all dependencies embedded: target/netty-plot-0.1-jar-with-dependencies.jar
.
If the application is expected to use some dynamic features at run time (e.g., Reflection, Java Native Interface, class path resources), they have to be provided to the native-image
tool in the form of configuration files.
To avoid writing the configuration file yourself, apply the tracing agent when running on the Java HotSpot VM.
It will observe the application behavior and create configuration files (jni-config.json, reflect-config.json, proxy-config.json and resource-config.json) in the META-INF/native-image directory on the class path.
The reflect-config.json file specifies classes which must be available via Java reflection at runtime.
-
Run the application on GraalVM JDK applying the tracing agent:
java -agentlib:native-image-agent=config-output-dir=src/main/resources/META-INF/native-image -jar target/netty-plot-0.1-jar-with-dependencies.jar
The server is started. Open http://127.0.0.1:8080/?useIsolate=false in the browser to see the output.
-
Terminate the application,
CTRL+C
. -
Build a native executable. The
native-image
builder will automatically search for any configuration file under META-INF/native-image and its subdirectories:native-image -jar target/netty-plot-0.1-jar-with-dependencies.jar
The result is an executable file that is around 22 MByte in size:
du -h netty-plot 22M netty-plot
-
You can now run the executable:
./netty-plot
Open your web browser and navigate to http://127.0.0.1:8080/
-
Finally, you can open your browser and request rendering of a function, for example, by browsing to
http://127.0.0.1:8080/?function=abs((x-31.4)sin(x-pi/2))&xmin=0&xmax=31.4
.
Instead of specifying any additional parameters on the command line, they may provided in a properties file in the input JAR file.
The native-image
builder automatically looks for files named native-image.properties
and for any other configuration file under META-INF/native-image
including subdirectories, and processes their contents.
The tracing agent writes the reflect-config.json file specifying classes which must be available via Java reflection at run time.
With Maven projects, the path convention is META-INF/native-image/${groupId}/${artifactId}/native-image.properties
.
In this example, the META-INF/native-image/com.oracle.substratevm/netty-plot/native-image.properties
file contains the following:
ImageName = netty-plot
Args = --link-at-build-time
The ImageName
property specifies the name of the resulting executable, while Args
are treated like additional command-line arguments.
This example cannot run as a regular Java application (on the JVM) and it cannot be profiled. It will fail because the program tries to create an isolate which is a Native Image specific feature.