Java 12に対応したexewrap 1.4リリース

Java 12 に対応した exewrap 1.4 をリリースしました。

exewrap 1.3.1 以前のバージョンで作成した実行ファイルを Java 12 で実行するとコンソールに以下の警告メッセージが表示されます。メッセージが表示されるだけでアプリケーションの動作自体には問題ありません

OpenJDK 64-Bit Server VM warning: Archived non-system classes are disabled because the java.system.class.loader property is specified (value = "Loader"). To use archived non-system classes, this property must not be set

この問題が exewrap 1.4 で改善しています。exewrap 1.4 で作成した実行ファイルであれば Java 12 実行環境でも上記のメッセージは表示されなくなります。

AdoptOpenJDK と組み合わせやすくなりました

他にも PATH 環境変数から Java 実行環境を見つけられるように改善されています。以前の exewrap ではシステムにインストールされた Java 実行環境を検索する方法が 2 つありました。JAVA_HOME 環境変数参照 レジストリ参照です。これらに PATH 環境変数参照による検索が加わりました。

Oracle JDK のインストーラーはインストールパスをレジストリに登録するので exewrap はレジストリ参照で Java 実行環境を見つけることができます。なんの問題もありません。

AdoptOpenJDK のインストーラーはデフォルトではレジストリを登録しません。Oracle JDK 互換のレジストリを書き込むオプションもありますが 気にせずに 次へ をクリックしていくとレジストリ登録されないままインストールが完了します。

Add to PATH オプションはデフォルトで有効になっており そのままインストールウィザードを進めた場合でも AdoptOpenJDK のインストールパスが PATH 環境変数に追加されます。exewrap 1.4 で作成したアプリは PATH 環境変数からも Java 実行環境を検索するため デフォルト構成でインストールした AdoptOpenJDK を見つけることができます。

exewrap 1.4 は以下のサイトからダウンロードできます。

この警告メッセージの意味は?

Java 12 で表示されるようになった警告メッセージの話に戻りましょう。

java.system.class.loader プロパティが指定されているため アーカイブされた非システムクラスは無効になります。アーカイブされたシステム以外のクラスを使用するには このプロパティを設定しないでください。

メッセージを日本語に訳すとこんな感じでしょうか。アーカイブされたクラスが無効になると書いてありますね。とても気になります。これはどういう意味なのでしょうか?

多くの Java 開発者は アーカイブ と聞いて JAR を思い浮かべると思います。JAR ファイル内のクラスがロードできなくなるのだとしたら大問題です。このメッセージを無視していいはずないのでは…

ご心配なく。このメッセージに出てくる アーカイブ JAR のことではありません。この アーカイブ というのは 共有アーカイブ JSA : Java Shared Archive のことです。

Java 5 J2SE 5.0 クラスデータの共有 CDS : Class Data Sharing という機能が追加されました。これは 複数の Java VM でクラスデータを共有することで プロセスの起動時間を短縮しメモリ使用量も抑えられるという機能です。このクラスデータの共有 CDS で使われるのが共有アーカイブ JSA です。キャッシュのようなものですね。なくて困るようなものではありません。現在の Java Hotspot VM は起動も速くなっており クラスデータ共有 CDS の恩恵はあまりないように思います

OpenJDK のバグ?

しかし このメッセージが表示されるのは OpenJDK のバグのようにも思えます。Java Hotspot VM にはクラスデータの共有を制御する以下のオプションがあります。

-Xshare:off
クラス データ共有を無効にします。
-Xshare:on
クラス データ共有の有効化を要求します。さまざまな理由で有効にできない場合は エラー メッセージを出力して終了します。
-Xshare:auto
デフォルト。可能な場合は常にクラス データ共有を有効にします。

Java Hotspot VM のデフォルトは -Xshare:auto であり 可能な場合はクラスデータを共有するという消極的な設定です。明示的に -Xshare:on を指定したときに 非システムクラスの共有が無効だと伝えるメッセージが表示されるのであれば理解できるのですが。

また このメッセージが表示された場合も 共有が無効になるのは非システムクラス ユーザークラス のみで 膨大な Java のシステムクラスのデータ共有は有効です。システムクラスに比べてユーザークラスのサイズは小さいですから ユーザークラスの共有が無効であっても影響は軽微です。デフォルトで警告メッセージを表示するようなことではないはずです。

本来なら明示的にユーザークラスの共有を指定した場合に限って表示すれば十分なメッセージでしょう。Java 9 まではシステムクラスの共有機能と ユーザークラスの共有機能は明確に区別されていました。ユーザークラスの共有機能は Oracle JDK の商用機能であり 明示的に -XX:+UnlockCommercialFeatures -XX:+UseAppCDS を指定する必要がありました。これらのオプション指定と カスタムシステムクラスローダーの指定が競合してユーザークラスの共有が無効になる状況であれば 警告メッセージが表示されるというのは分かりやすいです。

しかし Java 10 Java 11 で段階的にユーザークラス共有の扱いが変わっていきました。Java 10 でユーザークラスの共有は商用機能ではなくなり OpenJDK でも使用可能になりました。-XX:+UnlockCommercialFeatures を指定せずに -XX:+UseAppCDS が使えるようになりました さらに Java 11 では -XX:+UseAppCDS オプション自体が廃止になりました。クラスデータ共有が使える状況であれば システムクラス/ユーザークラスを問わず共有されるようになったからです。

システムクラスとユーザークラスを区別することがなくなり -XX:+UseAppCDS オプションの廃止によって ユーザークラス共有を有効化したい という意思を表示する手立てもなくなったことから Java 12 カスタムクラスローダーを使っていたら とりあえず クラスデータ共有無効の警告メッセージを表示しておくか となったのでしょうか? だとすれば ユーザービリティを無視した安易な決定だと感じます 😡

この記事を共有しませんか?