Skip to content

JEP 493: Linking Run-Time Images without JMODs | 不使用 JMOD 链接运行时镜像

摘要

通过启用 jlink 工具创建自定义运行时镜像而无需使用 JDK 的 JMOD 文件,将 JDK 的大小减少约 25%。此功能在构建 JDK 时必须启用;它不会默认启用,并且一些 JDK 供应商可能会选择不启用它。

目标

允许用户链接来自模块的运行时镜像,无论这些模块是独立的 JMOD 文件模块化 JAR 文件,还是先前链接的运行时镜像的一部分。

动机

在云环境中,JDK 在文件系统上的安装大小非常重要,因为包含已安装 JDK 的容器镜像会自动且频繁地从容器注册表通过网络复制。减少 JDK 的大小可以提高这些操作的效率。

一个完整安装的 JDK 有两个主要组件:一个 运行时镜像,即可执行的 Java 运行时系统,以及一组以 JMOD 格式 打包的 模块,用于运行时镜像中的每个模块。

当创建 自定义运行时镜像 时,JMOD 文件被 jlink 工具使用。完整 JDK 中的运行时镜像本身就是这样一个镜像,它是通过 jlink 从这些 JMOD 文件创建的。因此,运行时镜像中的每一个类文件、本地库、配置文件和其他资源也存在于这些 JMOD 文件之一中——可以说这是一种巨大的空间浪费。

实际上,完整 JDK 中的 JMOD 文件约占 JDK 总大小的 25%。如果我们能够增强 jlink 工具直接从运行时镜像提取类文件、本地库、配置文件和其他资源,那么我们可以通过省略 JMOD 文件显著减少已安装 JDK 的大小。

说明

新的 JDK构建时 配置选项 --enable-linkable-runtime 构建了一个 JDK,其 jlink 工具可以无需使用 JDK 的 JMOD 文件创建运行时镜像。生成的 JDK 不包括那些文件,即没有 jmods 目录。因此,与使用默认配置构建的 JDK 相比,它的大小大约减少了 25%,尽管它包含完全相同的模块。

bash
$ configure [ ... 其他选项 ... ] --enable-linkable-runtime
$ make images

任何 JDK 构建中的 jlink 工具都可以消费 JMOD 文件和模块化 JAR 文件。此外,在启用了此功能的 JDK 构建中,jlink 可以从其所属的运行时镜像消费模块。jlink--help 输出显示它是否具有这种能力:

bash
$ jlink --help
Usage: jlink <options> --module-path <modulepath> --add-modules <module>[,<module>...]
...
Capabilities:
      Linking from run-time image enabled
$

这意味着正在使用的 jlink 工具可以从包含的运行时镜像链接 JDK 模块。如果它不具备这种能力,则会显示 Linking from run-time image disabled

拥有新能力的 jlink 版本总是优先从模块路径上的 JMOD 文件(如果可用)消费 JDK 模块。仅当模块路径上找不到 java.base 模块时,它才会从其所属的运行时镜像消费模块。其他任何模块仍然需要通过 --module-path 选项指定给 jlink

使用具备新能力的 jlink 运行的用户体验与不具备该能力的 jlink 运行体验完全相同。如果想要通过省略某些模块来减小运行时镜像的大小,我们可以继续只包含所需的模块,而不需要 JMOD 文件。例如,要创建只包含 java.xmljava.base 模块的运行时镜像,jlink 调用是相同的:

bash
$ jlink --add-modules java.xml --output image
$ image/bin/java --list-modules
java.base@24
java.xml@24
$

jlink 的输出与从 JMOD 文件链接模块时完全相同。生成的运行时镜像比完整的 JDK 运行时镜像小约 60%。

对于更复杂情况的调用也是相同的。例如,假设我们想创建一个包含应用程序模块 app 及其所需库 lib 的运行时镜像。这些模块作为 模块化 JAR 文件 位于 mlib 目录中。我们通常通过 --module-path 选项将其指定给 jlink

bash
$ ls mlib
app.jar	lib.jar
$ jlink --module-path mlib --add-modules app --output app
$ app/bin/java --list-modules
app
lib
java.base@24
$

jlink 工具从模块化 JAR 文件 app.jarlib.jar 中复制了 applib 模块的类文件和资源。它从 JDK 的运行时镜像中提取 JDK 模块的类文件、本地库、配置文件和其他资源。

jlink--verbose 选项现在显示每个模块的来源:

bash
$ ls custom-jmods
foo.jmod
$ jlink --add-modules foo \
        --module-path=custom-jmods \
        --verbose \
        --output foo-image
Linking based on the current run-time image
java.base jrt:/java.base (run-time image)
foo file:///path/to/custom-jmods/foo.jmod

Providers:
  java.base provides java.nio.file.spi.FileSystemProvider used by java.base
$

这里,模块 java.base 是从当前运行时镜像中提取的,而模块 foo 是从 JMOD 文件 foo.jmod 链接来的。

不默认启用

默认的构建配置将保持现状:生成的 JDK 将包含 JMOD 文件,且其 jlink 工具将无法在没有这些文件的情况下运行。您从首选供应商处获得的 JDK 构建是否包含此功能取决于该供应商。

我们可能会在未来发布的版本中提议默认启用此功能。

限制

使用 --enable-linkable-runtime 选项构建的 JDK 中的 jlink 工具与使用默认配置构建的 JDK 相比有一些局限性:

  • jlink 不能用于创建本身包含 jlink 工具的运行时镜像。jlink 工具位于 jdk.jlink 模块中,因此以下操作会失败:

    bash
    $ jlink --add-modules jdk.jlink --output image
    错误:此 JDK 不包含打包的模块,并且无法用于创建包含 jdk.jlink 模块的另一个运行时镜像

    如果这被证明存在问题,我们将来可能会重新审视这一限制。

  • 如果修改了任何用户可编辑的配置文件,jlink 将会失败。

    JDK 的 conf 目录包含了开发人员可能编辑以配置 JDK 的各种文件。特别是 conf/security/java.security 文件,它配置了安全提供者、加密算法等。在默认构建中,jlink 从 JDK 的 JMOD 文件复制 JDK 模块的用户可编辑配置文件。没有 JMOD 文件,jlink 从运行时镜像复制配置文件,并在任何文件与原始文件不同的情况下失败:

    bash
    $ jlink --add-modules java.xml --output image
    错误:[...]/bin/conf/security/java.security已被修改

    此限制防止 jlink 创建具有临时或不安全配置的运行时镜像。如果安全配置被更改,例如启用了默认禁用的过时消息摘要算法,则将该配置复制到新的运行时镜像是不合适的。

  • 跨平台链接,例如,在 Linux/x64 上运行 jlink 以创建 Windows/x64 的运行时镜像,是不可能的。

  • 来自本身使用 --patch-module 选项的运行时镜像进行链接是不受支持的。

  • 通过从不同的运行时镜像中提取模块进行链接,例如,通过将该镜像指定给 --module-path 选项,是不受支持的。

替代方案

JDK 供应商可以单独提供 JDK 的 JMOD 文件作为独立下载。一些 Linux 发行版已经基本上做到了这一点,它们为 JDK 运行时镜像和相应的 JMOD 文件分别提供了安装包。

这种方法较为脆弱,因为如果未安装第二个软件包,则 jlink 工具将无法工作。此外,这种方法不适合云环境,在这种环境中,JDK 运行时镜像及其 JMOD 文件可能会最终位于不同且冲突的容器镜像层中。

Page Layout Max Width

Adjust the exact value of the page width of VitePress layout to adapt to different reading needs and screens.

Adjust the maximum width of the page layout
A ranged slider for user to choose and customize their desired width of the maximum width of the page layout can go.

Content Layout Max Width

Adjust the exact value of the document content width of VitePress layout to adapt to different reading needs and screens.

Adjust the maximum width of the content layout
A ranged slider for user to choose and customize their desired width of the maximum width of the content layout can go.