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)

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

with cjdk.java_env(vendor="graalvm-community", version="25.0.1"):
    subprocess.run(["javac", "Hello.java"], check=True)
    subprocess.run(["native-image", "Hello"], check=True)
cjdk: Installing JDK graalvm-community:25.0.1 to /home/runner/.cache/cjdk
========================================================================================================================
GraalVM Native Image: Generating 'hello' (executable)...
========================================================================================================================
For detailed information and explanations on the build output, visit:
https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/BuildOutput.md
------------------------------------------------------------------------------------------------------------------------
[1/8] Initializing...                                                                                    (5.1s @ 0.12GB)
 Java version: 25.0.1+8, vendor version: GraalVM CE 25.0.1+8.1
 Graal compiler: optimization level: 2, target machine: x86-64-v3
 C compiler: gcc (linux, x86_64, 13.3.0)
 Garbage collector: Serial GC (max heap size: 80% of RAM)
 1 user-specific feature(s):
 - com.oracle.svm.thirdparty.gson.GsonFeature
------------------------------------------------------------------------------------------------------------------------
Build resources:
 - 12.67GB of memory (75.6% of system memory, $CI set to 'true')
 - 4 thread(s) (100.0% of 4 available processor(s), determined at start)
[2/8] Performing analysis...  [******]                                                                  (17.9s @ 0.37GB)
    3,262 types,   3,721 fields, and  15,131 methods found reachable
    1,056 types,      36 fields, and     415 methods registered for reflection
       58 types,      59 fields, and      52 methods registered for JNI access
        0 downcalls and 0 upcalls registered for foreign access
        4 native libraries: dl, pthread, rt, z
[3/8] Building universe...                                                                               (2.4s @ 0.42GB)
[4/8] Parsing methods...      [*]                                                                        (1.8s @ 0.44GB)
[5/8] Inlining methods...     [****]                                                                     (1.9s @ 0.47GB)
[6/8] Compiling methods...    [****]                                                                    (19.2s @ 0.41GB)
[7/8] Laying out methods...   [*]                                                                        (1.4s @ 0.50GB)
[8/8] Creating image...       [*]                                                                        (1.7s @ 0.55GB)
   5.17MB (35.34%) for code area:     8,661 compilation units
   7.67MB (52.37%) for image heap:   88,461 objects and 55 resources
   1.80MB (12.29%) for other data
  14.64MB in total image size, 13.76MB in total file size
------------------------------------------------------------------------------------------------------------------------
Top 10 origins of code area:                                Top 10 object types in image heap:
   3.73MB java.base                                            1.39MB byte[] for code metadata
 902.15kB svm.jar (Native Image)                               1.19MB byte[] for java.lang.String
 110.59kB java.logging                                       828.48kB java.lang.String
  90.79kB org.graalvm.nativeimage.base                       626.30kB com.oracle.svm.core.hub.DynamicHubCompanion
  48.90kB jdk.proxy2                                         545.74kB heap alignment
  38.97kB jdk.proxy1                                         460.10kB byte[] for general heap data
  38.09kB org.graalvm.nativeimage.configure                  424.96kB java.lang.Class
  28.00kB jdk.internal.vm.ci                                 314.88kB java.util.HashMap$Node
  25.44kB jdk.graal.compiler                                 221.12kB java.lang.Object[]
  20.07kB org.graalvm.collections                            178.74kB java.util.HashMap$Node[]
  13.88kB for 5 more packages                                  1.48MB for 958 more object types
------------------------------------------------------------------------------------------------------------------------
Recommendations:
 FUTR: Use '--future-defaults=all' to prepare for future releases.
 HEAP: Set max heap for improved and more predictable memory usage.
 CPU:  Enable more CPU features with '-march=native' for improved performance.
------------------------------------------------------------------------------------------------------------------------
                        2.1s (3.9% of total time) in 491 GCs | Peak RSS: 1.14GB | CPU load: 3.62
------------------------------------------------------------------------------------------------------------------------
Build artifacts:
 /tmp/tmp99w44qf8/hello (executable)
========================================================================================================================
Finished generating 'hello' in 52.6s.

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