JEP draft: Linking Run-Time Images without JMODs

OwnerSeverin Gehwolf
TypeFeature
ScopeJDK
StatusSubmitted
Componenttools / jlink
Discussioncore dash libs dash dev at openjdk dot org
EffortM
DurationM
Reviewed byAlan Bateman, Mandy Chung
Created2024/06/07 13:36
Updated2024/10/09 19:44
Issue8333799

Summary

Reduce the size of the JDK by approximately 25% by enabling the jlink tool to create custom run-time images without having to include copies of the packaged JDK modules in the jmods directory.

Non-Goals

Motivation

The installed size of the JDK on the file system is important in cloud environments, where container images that include an installed JDK are automatically and frequently copied over the network from container registries. Reducing the size of the JDK would improve the efficiency of these operations.

When looking at the on-disk-size of a JDK installation we can see that the jmods directory takes up approximately 25% of the total installed size on the file system.

The following output with the Linux du ("disk usage") command line tool gives a sense of the size of the top two directories. Actual sizes will vary by platform and JDK vendor; in the sample output, the total size on the file system is 352MB.

$ du -sh jdk
352M jdk

$ du -s jdk/* | sort -n | tail -n2
87828    jdk/jmods
269784   jdk/lib

While the lib directory is the largest contributor (~264MB), almost all files in the lib folder are needed at run-time. The second largest contributor to the on-disk-size of the JDK is the jmods folder: ~85MB of ~352MB in total. This amounts to about 25% of the total size.

The jmods directory are files needed for running jlink in order to create custom run-time images. The directory contains a "packaged module", in JMOD format, for each standard module and each JDK-specific module in the run-time image. JMOD is a packaging format, like the JAR format, except that it additionally supports native code, configuration files and other resources. Unlike the JAR format, the JMOD format is not an executable format, the JDK does not load classes from jmod files, and you can not put jmod files on the java launcher's class path or module path.

What's more, the content of files in the jmods directory duplicate what is already present in the JDK image. The following example shows this for the java.lang.String class by extracting content from the jdk/lib/modules file and comparing it to the version in the java.base.jmod file. They are identical:

$ ./jdk/bin/jimage extract --dir ./extracted ./jdk/lib/modules
$ ./jdk/bin/jmod extract --dir java.base-extracted ./jdk/jmods/java.base.jmod
$ diff java.base-extracted/classes/java/lang/String.class ./extracted/java.base/java/lang/String.class

The jdk/lib/modules file contains the class files and resources for all modules in the run-time image. When an application runs, this is where the JDK loads the class files for java.lang.Object, java.lang.String and other classes in the java.* and jdk.* modules.

Similarly, native libraries of the JVM are present in the JMOD files and the installed JDK image:

$ ls jdk/lib/server/libjvm.so 
jdk/lib/server/libjvm.so
$ ./jdk/bin/jmod list ./jdk/jmods/java.base.jmod | grep libjvm.so
lib/server/libjvm.so

In summary we have:

It would greatly benefit the size of the JDK if the jlink tool did not require jmod files in the JDK run-time image and instead copied or reconstituted the class files, native code, and other resources from the run-time image itself.

Description

The new JDK build-time configuration option --enable-linkable-runtime builds a JDK whose jlink tool can create run-time images without using the jmods directory. When using this configuration option, no jmods directory will be created in the resulting JDK image.

$ configure [..other options..] --enable-linkable-runtime
$ make images

The resulting JDK is approximately 25% smaller on the file system when compared to the JDK that is built with the default configuration. The JDK contains exactly the same set of modules as the JDK created with the default configuration.

The jlink tool works exactly the same way as the jlink tool in a JDK created with the default configuration. For example, to create a run-time image containing only the java.xml and java.base module the jlink invocation works the same:

$ jlink --add-modules java.xml --output myimage
Linking based on the current run-time image.

$ myimage/bin/java --list-modules
java.base@24
java.xml@24

A further example creates a run-time image containing an application module named "app" that requires a library named "lib". These modules are packaged as modular JAR files in the mlib directory. The location of application modules linked into a custom run-time image need to be specified with the --module-path option as those modules wouldn't be present in the installed JDK image. JDK-specific modules will be linked from the installed run-time image.

$ ls mlib
app.jar	lib.jar

$ jlink --module-path mlib --add-modules app --output app
Linking based on the current run-time image.
$ app/bin/java --list-modules
app
lib
java.base@24

In this example, the class files and resources for modules "app" and "lib" are copied from the modular JAR files. The class files, native code, java launcher, and configuration files are copied from the JDK run-time image.

Restrictions

The jlink tool in a JDK build that was configured with --enable-linkable-runtime has a few limitations when compared to the jlink tool in a JDK build created with the default configuration:

Future Work

Future work may remove some or all of the restrictions listed above.

A future JEP may propose --enable-linkable-runtime be the default when building the JDK, thereby providing the benefit of smaller size on the file system to all distributions.

Alternatives

Provide the jmod files as a separate download. A number of Linux distributions already provide an OS installation package for the JDK that does not include the jmods directory. A separate OS installation package adds the .jmod files. This approach means that jlink tool fails if the separate OS installation package has not been downloaded and installed. It gets more difficult with container images that have the JDK installed but require a later step to install the separate OS installation package in order to use jlink.