JDK vs JRE: the structural picture

The JDK

The Java Development Kit is the full distribution: HotSpot (the JVM, in libjvm.so), the standard Java class library (java.* modules), the JDK tooling modules (jdk.*: Flight Recorder, JMX/RMI agent, jcmd attach, PKCS#11, the javac compiler, javadoc, jlink itself, etc.), and the CLI tools in bin/ (java, javac, jcmd, jlink, etc.). A typical JDK is ~300 MB.

What "Java SE" means as a module

Java SE is the standardised Java surface: the API portfolio in the Java Language Specification plus the Java Platform Specification. As a module, Java SE is named java.se in OpenJDK: an aggregator that requires every other java.* module (java.base, java.compiler, java.datatransfer, java.desktop, java.logging, java.management, java.net.http, java.rmi, java.sql, java.xml, and the rest of the SE module set). That is what --add-modules java.se to jlink gives you, and it is the API portfolio every "Java SE 25 compliant runtime" must expose.

The gap: jdk.* modules are NOT in Java SE

The JDK also ships modules that are outside the Java SE specification: JDK tooling modules with the jdk.* prefix:

ModuleWhat it provides
jdk.unsupportedsun.misc.Unsafe, sun.misc.Signal: "load-bearing" for the JVM ecosystem (Netty, Caffeine, Hazelcast, Lucene rely on it)
jdk.jfrFlight Recorder: continuous low-overhead profiling, the standard JVM observability primitive
jdk.management.agentJMX/RMI agent: for Prometheus exporters and monitoring tools
jdk.attachThe Attach API for jcmd, jconsole, or any tool to attach to a running JVM
jdk.crypto.cryptokiSunPKCS11: HSM / hardware-token crypto access
jdk.naming.dnsDNS SPI for JNDI
jdk.localedataNon-en_US locale resources (i18n)
jdk.zipfsThe jar: NIO Path provider

A Java SE-compliant JRE (i.e. jlink --add-modules java.se) does not include any of these. They are JDK tooling modules outside the Java SE specification.

This is the source of the apparent paradox the next section resolves: vendors that ship a "JRE" usually ship java.se only. Their JRE lacks Flight Recorder, JMX, and jcmd attach. The Eliya JRE adds them by default.

What jlink does

jlink is the OpenJDK tool that assembles a custom JRE-like runtime image from a chosen set of modules. Inputs:

  • A module path (where to find module JARs / JMODs)
  • A list of root modules (--add-modules X,Y,Z)
  • Options like --strip-debug, --no-man-pages, --no-header-files, --compress

jlink traces the transitive requires of the root modules, copies the resulting module closure plus the JVM runtime image, and produces a directory tree that looks like a JRE (bin/java, lib/, conf/). The resulting tree runs independently; it doesn't need a JDK on the host.

The --strip-debug flag

The --strip-debug option strips debug attributes from the class files inside the runtime image (line-number and local-variable tables); it does not strip native symbols from the shared libraries. The class code still works; you just lose class-file debug metadata. The size win comes from module curation plus class-file stripping, not from shrinking libjvm.so, which ships with its native symbols intact.

The --no-man-pages and --no-header-files flags

These drop man/man1/*.1 (the man-page snippets that are mostly redundant with --help) and include/*.h (the JNI header files for native code authors). Production servers don't read man pages from the runtime image; they get them from the OS man database.

Eliya's curation: the 10 modules

The Eliya JRE includes:

ModuleWhy included
java.seThe Java SE aggregator: pulls in every standard Java SE module
java.net.httpHTTP/2 client (explicit; also pulled via java.se, listed for visibility)
jdk.unsupportedEffectively required by the JVM ecosystem (Netty, Caffeine, Hazelcast, …)
jdk.crypto.cryptokiForward-looking: HSM-backed crypto needed for Phase 4 hardware-token work
jdk.jfrFlight Recorder: the OpenJDK community has standardised on JFR for production profiling. Operators expect jcmd <pid> JFR.start to work without switching to the JDK.
jdk.management.agentJMX/RMI agent: Prometheus exporters, monitoring agents, and operational tools attach via JMX
jdk.attachThe Attach API: local jcmd works without it; remote / external tool attach requires it
jdk.naming.dnsDNS SPI for JNDI
jdk.localedataNon-en_US locales: i18n surface for production servers handling international data
jdk.zipfsThe jar: NIO Path provider: tools that walk into ZIP/JAR archives via NIO

Combined with --strip-debug, --no-man-pages, and --no-header-files, the resulting image is ~48 MB compressed (~74 MB extracted).

How the size stays compact

The Eliya JRE adds 9 extra modules on top of the standard java.se set and extracts to 74 MB. Two jlink mechanisms account for most of the size win:

  1. Module curation. The full upstream OpenJDK 25 module set is around 80 modules. Eliya's JRE includes only the modules production servers use (the java.se aggregator plus the nine jdk.* modules listed below). Modules not included are not present in the assembled runtime image at all.
  2. JIMAGE compression. jlink's --compress option compresses the class files inside lib/modules at build time. The compression cost is paid once at build; runtime decompression happens on demand and is negligible.

The 9 extra jdk.* modules add a few megabytes collectively. Net: a 49 MB compressed tarball that extracts to 74 MB with a more complete production module set than a java.se-only baseline.

Note: jlink's --strip-debug flag strips class-file debug attributes inside the modules, not native symbols. The native shared libraries (libjvm.so, etc.) retain their symbols in this build.

Trade-offs

Every choice has costs. Eliya's JRE choices and their trade-offs:

ChoiceCost
--strip-debugCan't gdb into HotSpot from a stripped JRE. Mitigation: install the Eliya JDK alongside if you need to debug, or use the JDK download.
Include jdk.jfr, jdk.management.agent, jdk.attach~5-7 MB heavier than a Java-SE-only JRE; some consumers don't need diagnostics. Mitigation: future Eliya variants (Docker -slim, -jre-distroless) can omit these.
Include jdk.localedata~10 MB i18n resources for non-en_US locales. Many server deployments only need en_US. Mitigation: the future -slim variant drops this.
Include jdk.crypto.cryptoki~1 MB PKCS#11 provider. Not all deployments use HSMs. Mitigation: low marginal cost; left in.
--no-man-pages, --no-header-filesJNI code authors who compile against the runtime image need separate headers. Mitigation: use the Eliya JDK for native dev.

The non-Eliya alternative: jlink your own

The architectural beauty of jlink is that any user can produce their own custom runtime image from any vendor's JDK. Customers don't need the Eliya JRE; they could run:

…using the Eliya JDK, the Temurin JDK, the Corretto JDK, or any other vendor's JDK. The result is a runtime they own. Eliya's JRE saves customers that step and provides a curated, signed, reproducible default. The argument for Eliya's JRE is convenience + the reproducibility/signing/audit-trail story attached to it, not "you can't do this yourself".

Forward-looking

Eliya plans four container variants, each with its own module curation:

VariantModule setTarget use
Full JDK (shipping in 25.0.3)Everything in the JDKDeveloper machines, CI builders
-slim (Phase 2)Eliya JRE minus jdk.localedata and other non-server modulesContainer deployments, en_US production
-jre (Phase 2)The Eliya JRE as described on this pageContainer-native applications
-jre-distroless (Phase 2)The Eliya JRE on gcr.io/distroless/base for minimal attack surfaceSecurity-conscious containers

When Eliya transitions to JDK 27 (post-Phase 1), the module set will be re-validated against JDK 27's module changes. JDK 27 may add modules (e.g. structured concurrency improvements) we want to include; we may also drop modules whose use case has receded.

[ } Eliya Eliya Dial Dial
Privacy
[ }
[ }
// PRODUCTS Eliya Eliya Dial Dial