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
- It is not a goal at this time to make the JDK build time option the default.
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:
- The
jmods
directory contributes a significant amount of on-disk-size as compared to the total JDK installation size: approximately 25%. - Files in the
jmods
directory are used only byjlink
when creating custom run-time images, but aren't used at application run-time. - Yet, files in the
jmods
directory duplicate content available elsewhere in the installed JDK image.
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:
jlink
cannot be used to create a run-time image that itself contains thejlink
tool. Thejlink
tool is in thejdk.jlink
module and the following fails:$ jlink --add-modules jdk.jlink --output image Error: This JDK does not contain packaged modules and cannot be used to create another run-time image that includes the jdk.jlink module.
This restriction may be re-visited in the future if it proves problematic.
jlink
fails if user-editable configuration is modified. The JDKconf
directory contains.properties
and other files that a developer may edit to configure the JDK. One example isconf/security/java.security
which contains the configuration for security providers, algorithms and more. With the default build, the user-editable configuration files for the java.* and jdk.* modules are copied from the packaged modules (thejmod
files). Without the packaged modules, the configuration files are copied from the run-time image andjlink
fails if any of the files are different from the original files.$ jlink --add-modules java.xml --output image Linking based on the current run-time image. Error: [...]/bin/conf/security/java.security has been modified.
This restriction is necessary to prevent
jlink
creating a run-time image with ad hoc or insecure configuration. If the security configuration is changed, e.g. changed to enable an obsolete message digest algorithm that is disabled by default, then it would be inappropriate to copy this configuration to the new run-time image.Cross-linking, e.g., running
jlink
on Linux x64 to create a run-time image for Windows x64, is no longer possible.
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
.
- relates to
-
JDK-8311302 Allow for jlinking a custom runtime without packaged modules being present
- In Progress