Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Under the hood: Quarkus Native Choices and Impl...

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.

Under the hood: Quarkus Native Choices and Implementation

In this presentation, we will take a detailed look at how Quarkus implements native compilation with GraalVM, highlighting the architectural choices that set it apart from other frameworks.

We will start with an overview of the Quarkus “Build-time” model, specifically how it pre-processes application segments to minimize the heavy lifting usually required at runtime. From there, we will dive into the specific trade-offs made during the native image generation process—explaining the “why” behind the configuration and optimization decisions.

To wrap up, we will go directly into the Quarkus source code to show:

How these decisions are practically implemented
How Quarkus “fixes” third-party libraries for native compatibility without changing their original code
The tangible performance benefits these implementation details provide to the end user.

Avatar for zakkak

zakkak

July 08, 2026

More Decks by zakkak

Other Decks in Programming

Transcript

  1. Under the hood: Quarkus Native Choices and Implementation Foivos Zakkak,

    Software Engineer at @foivos.zakkak.net @zakkak @foivoszakkak with
  2. @ @ </> The Traditional vs. Quarkus Ways @ @

    </> Build Time Runtime Runtime Build Time
  3. Pros Faster startup Close to peak performance from the beginning

    Small standalone binary Smaller memory footprint (RSS)
  4. Pros and Cons Faster startup Close to peak performance from

    the beginning Small standalone binary Smaller memory footprint (RSS) Slower development cycle Lower peak performance Security patches require recompilation Not portable Lacks behind in terms of tooling support
  5. Substrate VM Classes JDK Classes JDK Classes Substrate VM Classes

    Java Application Classes Java Application Classes Native Executable AOTC - GraalVM native image - Dead code elimination Dead Code Elimination Static Analysis Native Compilation
  6. OK with caveats in usage • Reflection (manual list) •

    Dynamic proxy (manual list) • JNI (manual list) • Unsafe Memory Access (manual list) • Static initializers (eager) • Threads (Long-deprecated methods missing) • FFM API (manual list) • Security Manager (different behavior) Not supported or limited support • Dynamic classloading • invokedynamic bytecode • Finalizers • JVMTI, JMX, native VM Interfaces The Dark Side https://www.graalvm.org/jdk25/reference-manual/native-image/metadata/Compatibility/
  7. Drives the gathering of metadata needed by GraalVM Most of

    the ecosystem already supported on GraalVM • based on framework knowledge • Classes using reflection, resources, etc • No need for agent + prerun, long JSON metadata or manual command lines Minimizes dependencies Helps static analysis with dead code elimination How does Quarkus native help developers?
  8. Quarkus Native defaults • Build time initialization of all classes

    (where possible) ◦ Re-initialize when necessary (e.g. random seeds, platform specific values, etc.) ◦ Reset fields to null to prevent pulling in undesired state or classes • Doesn’t allow incomplete classpaths (--link-at-build-time) ◦ No unexpected runtime failures due to ClassNotFoundException • Mandrel: Downstream distribution of GraalVM CE based on Eclipse Temurin OpenJDK builds and specifically tailored to Quarkus (maintained by )
  9. Implementation • GraalVM native-image JSON configuration generation • Custom features

    • Code substitutions (com.oracle.svm.core.annotate.Substitute) • Dynamic GraalVM feature generation • Default configuration overrides and parameterization of native builds
  10. JSON configuration files generation Automatically generates: • META-INF/native-image/jni-config.json • META-INF/native-image/proxy-config.json

    • META-INF/native-image/reflect-config.json • META-INF/native-image/resource-config.json • META-INF/native-image/serialization-config.json Handled by io.quarkus.deployment.steps.NativeImage*ConfigStep Based on present build items io.quarkus.deployment.builditem.nativeimage.*BuildItem • Typically provided by the core framework and its extensions
  11. JSON configuration files generation Moving to reachability-metadata.json in Quarkus 4

    with Mandrel 25.0: • META-INF/native-image/jni/reachability-metadata.json • META-INF/native-image/proxy/reachability-metadata.json • META-INF/native-image/reflect/reachability-metadata.json • META-INF/native-image/resource/reachability-metadata.json • META-INF/native-image/serialization/reachability-metadata.json See https://github.com/quarkusio/quarkus/pull/53546
  12. Custom Features Quarkus uses 29 static Features for things that

    are not dynamic, e.g.: • AWT support • Brotli4J support • Snappy support • Work-around logging issues at native-image build time • Etc.
  13. Substitutions: Statistics in Quarkus core 304 method substitutions and 33

    field re-computations in 215 classes • To assist in dead code elimination • To make code compatible with build time initialization
  14. Substitutions: Example @TargetClass(className = "io.netty.handler.codec.compression.ZstdEncoder", onlyWith = IsZstdAbsent.class) public static

    final class ZstdEncoderFactorySubstitution { @Substitute protected ByteBuf allocateBuffer(ChannelHandlerContext ctx, ByteBuf msg, boolean preferDirect) throws Exception { throw new UnsupportedOperationException(); }
  15. Substitutions: Example public static class IsZstdAbsent implements BooleanSupplier { @Override

    public boolean getAsBoolean() { try { Class.forName("com.github.luben.zstd.Zstd"); return false; } catch (Exception e) { return true; } } }
  16. Substitutions: Recompute Field Reset Example @TargetClass(className = "org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider", onlyWith =

    BouncyCastleCryptoFips.class) final class Target_org_bouncycastle_jcajce_provider_BouncyCastleFipsProvider { @Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) // // yes, typo on bcfips side. private SecureRandom entopySource; }
  17. Substitutions: Recompute Field FromAlias Example @TargetClass(className = "io.netty.handler.ssl.OpenSsl") final class

    Target_io_netty_handler_ssl_OpenSsl { @Alias @RecomputeFieldValue(kind = Kind.FromAlias) private static Throwable UNAVAILABILITY_CAUSE = new RuntimeException("OpenSsl unsupported on Quarkus"); … @Substitute public static boolean isAvailable() { return false; } …
  18. Feature Generation Handled by io.quarkus.deployment.steps.NativeImageFeatureStep Uses io.quarkus.gizmo for bytecode generation

    Necessary to register/configure anything that’s not possible through JSON config
  19. Feature Generation - Example if (!runtimeInitializedPackageBuildItems.isEmpty()) { b2.block(b3 -> {

    b3.invokeStatic(INITIALIZE_PACKAGES_AT_RUN_TIME, b3.newArray(String.class, runtimeInitializedPackageBuildItems.stream() .map(RuntimeInitializedPackageBuildItem::getPackageName) .map(Const::of) .toArray(Expr[]::new))); }); }
  20. GraalVM defaults override: Example addExperimentalVMOption(nativeImageArgs, "-H:+AllowFoldMethods"); if (nativeConfig.headless()) { nativeImageArgs.add("-J-Djava.awt.headless=true");

    // Default } if (nativeConfig.enableFallbackImages()) { nativeImageArgs.add("--auto-fallback"); } else { nativeImageArgs.add("--no-fallback"); // Default } if (!classpathIsBroken) { nativeImageArgs.add("--link-at-build-time"); // Default }
  21. Adaptation based on underlying native-image version /* * Always install

    exit handlers, it will become the default and the flag will * be deprecated in GraalVM for JDK 25 * see https://github.com/quarkusio/quarkus/issues/47799 */ if (graalVMVersion.compareTo(GraalVM.Version.VERSION_25_0_0) < 0) { nativeImageArgs.add("--install-exit-handlers"); }