Java 24 で導入 JEP 493 Linking Run-Time Images without JMODs

blog1.mammb.com


JEP 493 Linking Run-Time Images without JMODs まとめ

  • JDKベンダがJDKをビルドする際に指定可能なオプション --enable-linkable-runtime が追加された(JDK利用者側は特に気にすることはない)
  • --enable-linkable-runtime オプションが有効な場合、JDK に含まれるJMODファイルが省略される
  • JMODファイルは jlink ツールで利用されていたが、--enable-linkable-runtime オプションが有効な場合は、jlink ツールが自身でランタイムイメージから必要なリソースを抽出するようになったため、JMODファイルが省略可能
  • --enable-linkable-runtime はあくまでJDK自身のビルドオプションであり、オプションを有効にするかどうかはJDKベンダ次第
  • JMODファイルが省略されることで、JDK自体のサイズが約25%削減できる
  • コンテナ・イメージは、コンテナ・レジストリから頻繁にコピーされるため、JDKのインストール・サイズを縮小することが効率的


以下 JEP 内容


Summary

jlink ツールを拡張し、JMODファイルを使わずにカスタムランタイムイメージを作成できるようにします。 これによりJDKのサイズが約25%削減できます。 この機能はJDKのビルド時に有効にする必要があり、デフォルトでは有効になりませんし、JDKベンダーによっては有効にしないことを選択する場合もあります。

Goals

モジュールが、スタンドアロンの JMODファイルモジュールJARファイル、または以前にリンクされたランタイムイメージの一部であるかによらず、ランタイムイメージをリンクできるようにします。

Motivation

クラウド環境では、インストールされたJDKを含むコンテナ・イメージが、コンテナ・レジストリからネットワーク経由で自動的かつ頻繁にコピーされるため、ファイルシステム上のJDKのインストール・サイズは重要になります。JDKのサイズを小さくすれば、こうした作業が効率化されます。

JDKには、2つの主要なコンポーネントがあります。 1つは実行可能なJavaランタイム・システムである「ランタイム・イメージ」、もう1つはランタイム・イメージの各モジュールに対応するJMODフォーマットの「パッケージ・モジュール」です。

JMODファイルは jlink ツールが カスタムランタイムイメージ を作成するときに使用します。 JDK に含まれるランタイムイメージは、それ自身がランタイムイメージであり、jlink を介して JMOD ファイルから作成されます。 したがって、ランタイムイメージ内のすべてのクラスファイル、ネイティブライブラリ、設定ファイル、その他のリソースは、JMODファイルの中に重複して存在しています。

実際、完全なJDKのJMODファイルはJDKの総サイズの約25%を占めています。 もし jlink ツールを拡張して、ランタイムイメージ自体からクラスファイル、ネイティブライブラリ、設定ファイル、その他のリソースを抽出することができれば、JMODファイルを省くことでインストールされるJDKのサイズを劇的に小さくすることができます。

Description

新しい JDK build-time 設定オプション --enable-linkable-runtime は、 jlink ツールが JDK の JMOD ファイルを使用せずにランタイムイメージを作成できるように JDK をビルドします。 この場合、 jmods ディレクトリは存在しなくなり、デフォルトの設定でビルドされたJDKより約25%小さくなります。

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

jlink ツールは、JMOD ファイルとモジュール化された JAR ファイルの両方を利用することができることは変わりません。--enable-linkable-runtime が有効になっている JDK ビルドでは、 jlink はその一部であるランタイムイメージからモジュールを使うことができます。

jlink--help 出力には、このオプション有無が表示されます。

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

run-time-image トークンは、使用する jlink ツールがランタイムイメージから JDK モジュールをリンクできることを意味します。 この機能がない場合、トークンは -run-time-image です。

新しい機能を持つ jlink のバージョンは、利用可能であれば、常にモジュールパス上の JMOD ファイルから JDK モジュールを利用することを優先します。 モジュールパス上に java.base というモジュールが見つからない場合のみ、そのモジュールが属するランタイムイメージからモジュールを消費します。 その他のモジュールは --module-path オプションで jlink に指定する必要があります。

新しい機能を使って jlink を実行したときのユーザーエクスペリエンスは、機能なしで jlink を実行したときとまったく同じになります。 いくつかのモジュールを省いてランタイムイメージのサイズを小さくしたい場合、必要なモジュールだけを含めれば、JMODファイルは必要なくなります。 例えば、java.xmljava.base モジュールだけを含むランタイムイメージを作成する場合、jlink の呼び出しに変化はありません。

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

jlinkの出力は、モジュールがJMODファイルからリンクされた場合とまったく同じです。結果として得られるランタイムイメージは、完全なJDKランタイムイメージよりも約60%小さくなります。

より複雑な呼び出しでも同じです。例えば、ライブラリ lib を必要とするアプリケーションモジュール app を含むランタイムイメージを作成したいとします。 これらのモジュールは モジュール型 JAR ファイル として mlib ディレクトリにパッケージされていた場合、今まで通りに --module-path オプションを使って jlink にモジュールを指定します。

$ 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 モジュールのクラスファイルとリソースをコピーします。 jlink ツールは JDK のランタイムイメージから JDK モジュールのクラスファイル、ネイティブライブラリ、設定ファイル、その他のリソースを抽出します。

jlink--verboseオプションは各モジュールのオリジンを表示するようになります。

$ 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 からリンクされていることを示します。

Not enabled by default

デフォルトのビルド構成は現状のまま変更はありません。 出来上がったJDKにはJMODファイルが含まれ、jlinkツールはJMODファイルなしでは動作しません。 JDKビルドにこの機能が含まれているかどうかは、JDKベンダ次第になります。

将来のリリースでは、この機能をフォルトで有効にすることを提案する可能性があります。

Restrictions

enable-linkable-runtimeでビルドされたJDKのjlinkツールは、デフォルトの設定でビルドされたJDKのものと比べて、いくつかの制限があります。

  • jlink ツールを含むランタイムイメージを作成するために jlink を使用することはできません。jlink ツールは jdk.jlink モジュールに含まれているので、以下は失敗します(将来、この制限が問題になるようであれば、再検討する可能性があります)

      $ 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
    
  • ユーザが変更可能な設定ファイルが編集されると jlink は失敗します

JDKの conf ディレクトリには、開発者がJDKを設定するために編集する様々なファイルが含まれています。 特に conf/security/java.security ファイルは、セキュリティプロバイダや暗号アルゴリズムなどを設定します。 デフォルトのビルドでは、 jlink は JDK の JMOD ファイルから JDK のモジュールのユーザが編集可能な設定ファイルをコピーします。 JMOD ファイルがない場合、jlink はランタイムイメージから設定ファイルをコピーし、元のファイルと異なるファイルがあると失敗します

```shell
$ jlink --add-modules java.xml --output image
Error: [...]/bin/conf/security/java.security has been modified
```

この制限は jlink がアドホックまたは安全でない設定でランタイムイメージを作成するのを防ぎます。セキュリティ設定が、例えば、デフォルトでは無効になっている旧式のメッセージダイジェストアルゴリズムを有効にするように変更された場合、その設定を新しいランタイムイメージにコピーすることは不適切です。

  • Linux/x64上でjlinkを実行してWindows/x64用のランタイム・イメージを作成するといったクロスリンクはできない
  • patch-moduleを使用しているランタイムイメージからのリンクはサポートされない
  • --module-pathオプションに別のランタイムイメージを指定するなど、別のランタイムイメージからモジュールを抽出してリンクすることはサポートされない

Alternatives

JDKベンダは、JDKのJMODファイルを別のダウンロードとして提供することができます。 いくつかのLinuxディストリビューションは既に、JDKのランタイムイメージと、それに対応するJMODファイルのインストールパッケージを提供しています。

2つ目のパッケージがインストールされていないと jlink ツールは動作しないので、このアプローチは脆く、JDKランタイムイメージとJMODファイルが異なるコンテナイメージ層で競合する可能性があるクラウド環境には適していません。