Building and running a GraalVM native image

Building and running a GraalVM native image#

This example shows how to compile Java source code into a native image (executable that does not require the JVM) using GraalVM.

Note that some platform-specific prerequisites must be installed for this to work; see the GraalVM documentation for details.

import cjdk
import subprocess
java_source = """
public class Hello {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}
"""
with open("Hello.java", "w") as fp:
    fp.write(java_source)

Let’s store the keyword arguments to cjdk.java_env() so that we can call it several times with the same configuration.

cjdk_config = dict(vendor="graalvm-java17", version="22.1.0")

The GraalVM native-image command is not included in the default install, so we need to use gu (the GraalVM updater) to install it.

(On macOS, you may see warnings related to setrlimit in this and following steps. They can be ignored.)

with cjdk.java_env(**cjdk_config):
    subprocess.run(
        ["gu", "install", "--no-progress", "native-image"], check=True
    )
cjdk: Installing JDK graalvm-java17:22.1.0 to /home/runner/.cache/cjdk
Downloading: Component catalog from www.graalvm.org
Processing Component: Native Image
Downloading: Component native-image: Native Image from github.com
Installing new component: Native Image (org.graalvm.native-image, version 22.1.0)

Now let’s compile the source, first with javac to byte code, then to a native image.

with cjdk.java_env(**cjdk_config):
    subprocess.run(["javac", "Hello.java"], check=True)
    subprocess.run(["native-image", "Hello"], check=True)
========================================================================================================================
GraalVM Native Image: Generating 'hello' (executable)...
========================================================================================================================
[1/7] Initializing...                                                                                    (4.4s @ 0.19GB)
 Version info: 'GraalVM 22.1.0 Java 17 CE'
 C compiler: gcc (linux, x86_64, 11.4.0)
 Garbage collector: Serial GC
[2/7] Performing analysis...  [******]                                                                  (13.7s @ 0.60GB)
   2,852 (74.19%) of  3,844 classes reachable
   3,399 (50.83%) of  6,687 fields reachable
  12,932 (44.56%) of 29,020 methods reachable
      27 classes,     0 fields, and   345 methods registered for reflection
      57 classes,    58 fields, and    51 methods registered for JNI access
[3/7] Building universe...                                                                               (1.1s @ 0.80GB)
[4/7] Parsing methods...      [*]                                                                        (1.0s @ 1.05GB)
[5/7] Inlining methods...     [****]                                                                     (1.5s @ 0.57GB)
[6/7] Compiling methods...    [***]                                                                     (10.6s @ 1.25GB)
[7/7] Creating image...                                                                                  (1.4s @ 1.56GB)
   4.41MB (35.36%) for code area:    7,591 compilation units
   6.97MB (55.89%) for image heap:   1,711 classes and 102,361 objects
   1.09MB ( 8.75%) for other data
  12.47MB in total
------------------------------------------------------------------------------------------------------------------------
Top 10 packages in code area:                               Top 10 object types in image heap:
 666.57KB java.util                                         1014.06KB byte[] for general heap data
 338.23KB java.lang                                          984.94KB java.lang.String
 274.64KB java.text                                          944.53KB byte[] for code metadata
 235.70KB java.util.regex                                    645.59KB java.lang.Class
 194.32KB com.oracle.svm.jni                                 572.10KB byte[] for java.lang.String
 193.15KB java.util.concurrent                               474.56KB java.util.HashMap$Node
 157.78KB com.oracle.svm.core.reflect                        222.81KB com.oracle.svm.core.hub.DynamicHubCompanion
 147.39KB java.math                                          201.63KB java.lang.String[]
  98.45KB java.util.logging                                  197.61KB java.util.HashMap$Node[]
  94.89KB com.oracle.svm.core.genscavenge                    155.91KB java.util.concurrent.ConcurrentHashMap$Node
      ... 119 additional packages                                 ... 778 additional object types
                                           (use GraalVM Dashboard to see all)
------------------------------------------------------------------------------------------------------------------------
                        1.6s (4.5% of total time) in 17 GCs | Peak RSS: 3.47GB | CPU load: 3.65
------------------------------------------------------------------------------------------------------------------------
Produced artifacts:
 /tmp/tmpc80ahs7a/hello (executable)
 /tmp/tmpc80ahs7a/hello.build_artifacts.txt
========================================================================================================================
Finished generating 'hello' in 34.8s.

Finally, let’s run the native image. Being a native image, it does not need java_env() to run:

r = subprocess.run(["./hello"], check=True)
Hello, World!
r.returncode
0