https://openjdk.java.net/jeps/310
JEP 310: Application Class-Data Sharing
Owner Ioi Lam Type Feature Scope Implementation Status Closed / Delivered Release 10 Component hotspot / runtime Discussion hotspot dash dev at openjdk dot java dot net Reviewed by Karen Kinnear, Mikael Vidstedt, Vladimir Kozlov Endorsed by Mikael Vidstedt, Vladimir Kozlov Created 2017/08/08 22:02 Updated 2018/08/17 20:35 Issue 8185996
Summary
起動時間とフットプリント改善目的で、既存のClass-Data Sharing ("CDS")でアプリケーションクラスを共有アーカイブ内に配置可能なように拡張します。
Goals
- 異なるJavaプロセス間で共通のクラスメタデータを共有する事によりフットプリントを削減。
- 起動時間の改善。
- JDKランタイムイメージファイル(
$JAVA_HOME/lib/modules
)のアーカイブクラスとプラットフォームおよびシステムクラスローダにロードされるアプリケーションクラスパスを使えるようにCDSを拡張。 - アーカイブクラスをカスタムクラスローダにロード出来るようにCDSを拡張。
Non-Goals
- 本実装で使用する共有クラスのアーカイブストレージフォーマットの標準化はしない。
- 本リリースでは、CDSはユーザ定義モジュール(ex.
--module-path
で定義する)のクラスはアーカイブしない。将来リリースでサポート予定。
Success Metrics
本プロジェクトは、(1)複数JVMプロセス間でJavaのクラスメタデータが使用するメモリの著しい削減(2)スタートアップ時間の著しい改善、が達成出来れば成功と考えられます。
実際に適用例としては、
- あるJava EEサーバで6個のJVMプロセスが合計13GB(クラスメタデータに2GB)消費するケースで約340MBを削減可能。
- JEditベンチマークのスタートアップ時間を20-30%改善。
- 組み込みFelixベンチマークのRAM使用量を4個のJVMプロセスで18%改善。
上記の数値は特定のベンチマーク下であり一般的に言えるとは限りません。クラスローダがロードするクラス数およびアプリケーション全体のヒープ使用量に依存します。
Description
JDK 5で導入したClass-Data Sharingは事前にクラスを共有アーカイブにすることで起動時間改善のため実行時にメモリマッピングします。また、複数JVMが同一アーカイブファイルを共有する場合、動的にメモリフットプリントを削減します。
現行のCDSはアーカイブクラスのロードにはブートストラップクラスローダのみ使用可能です。Application CDS ("AppCDS")はCDSを拡張し、ビルトインシステムクラスローダ(別名"app class loader")・ビルトインプラットフォームクラスローダ・アーカイブクラスロード用のカスタムクラスローダ、を使用可能です。
大規模エンタープライズアプリケーションのメモリ使用分析によると、アプリケーションクラスローダに数万クラスをロードします。こうしたアプリケーションにAppCDSを適用するとJVMプロセスごとに数十から数百MBを削減可能です。
サーバレスクラウドサービスの分析によると、起動時に数千アプリケーションクラスをロードします。AppCDSでサービスの起動時間短縮とシステムレスポンスタイム全体を改善できます。
Enabling AppCDS
デフォルトでは、Class-Data SharingはJVMのブートストラップクラスローダでだけ有効化されています。-XX:+UseAppCDS
コマンドラインオプション指定により、システムクラスローダ(別名"app class loader")・プラットフォームクラスローダ・その他のユーザ定義クラスローダ、でクラスデータ共有を有効化します。
Determining the classes to archive
多数のクラスでアプリケーションをパッケージしても、通常の実行ではそれらの一部のみしか使用しない事が多いです。そうした使用するクラスのみのアーカイブ化により、ファイルストレージサイズと実行時のメモリ使用量を削減します。これを行うには、まず-Xshare:off
でアプリケーションを通常実行する際に-XX:DumpLoadedClassList
でロードされる全クラスを記録します。
注意点としてデフォルトでは-XX:DumpLoadedClassList
はブートストラップクラスローダがロードするクラスのみ含みます。-XX:+AppCDS
オプション指定により、システムクラスローダ・プラットフォームクラスローダがロードするクラスも含むようになります。以下は例です。
java -Xshare:off -XX:+UseAppCDS -XX:DumpLoadedClassList=hello.lst -cp hello.jar HelloWorld
Creating the AppCDS archive
AppCDSアーカイブを生成するには、-Xshare:dump -XX:+UseAppCDS
オプションを指定し、-XX:SharedClassListFile
にクラスのリストを指定し、アプリケーションで使用するのと同じクラスパスを指定します。また、-XX:SharedArchiveFile
にクラスを格納するアーカイブファイル名を指定します。注意点として、-XX:SharedArchiveFile
が未指定の場合、アーカイブされるクラスはJDKインストールディレクトリに保存されます。
$ java -Xshare:dump -XX:+UseAppCDS -XX:SharedClassListFile=hello.lst \
-XX:SharedArchiveFile=hello.jsa -cp hello.jar
Using the AppCDS archive
AppCDSアーカイブを生成したら、アプリケーション開始時にそれを使用します。-Xshare:on -XX:+UseAppCDS
オプションと、アーカイブファイル名を指定する-XX:SharedArchiveFile
を指定して実行します。
$ java -Xshare:on -XX:+UseAppCDS -XX:SharedArchiveFile=hello.jsa \
-cp hello.jar HelloWorld
Classpath mismatch
-Xshare:dump
のクラスパスは、-Xshare:on
のクラスパスと同一もしくはプレフィクスの必要があります。そうでない場合、JVMはミスマッチのクラスパスのエラーメッセージを表示して停止します。ミスマッチの調査には、-Xlog:class+path=info
を追加すると、JVMは期待されるクラスパスと実際に使用されたクラスパスに関する詳細な診断情報を出力します。
Using -Xshare:auto
AppCDSの動作は固定アドレスにアーカイブをメモリマッピングします。ある種のOSでは、address space layout randomization (ASLR)が有効の場合には特に、要求アドレス空間が利用不可能な場合にメモリマッピング操作が失敗することがあります。-Xshare:on
を指定する場合、JVMはこれをエラーとして扱い起動を失敗します。この場合にアプリケーションを柔軟に対処させるには、代わりに-Xshare:auto
を推奨します。この場合、JVMがアーカイブのメモリマッピングに失敗すると、AppCDSを無効化してアプリケーションを通常実行します。
なお、-Xshare:auto
はクラスパスのミスマッチの場合にもAppCDSを無効化します。よって、まずミスマッチが無いことを-Xshare:on
でテストしてから本番環境で-Xshare:auto
にするのを推奨します。
Listing the Classes Loaded from the AppCDS Archive
AppCDSアーカイブからロードされたクラスを参照するには-Xlog:class+load=info
を使います。ロードされたクラス名とどこからロードされたかを表示します。CDSアーカイブからロードされたクラスはsource: shared objects file
の形で表示します。
$ java -Xshare:on -XX:+UseAppCDS -XX:SharedArchiveFile=hello.jsa \ -cp hello.jar -Xlog:class+load=info HelloWorld | grep HelloWorld [0.272s][info][class,load] HelloWorld source: shared objects file
Implementation
- Platform and system class loaders: HotSpot VMはプラットフォームとシステムクラスローダのクラスロード要求を解釈します。これらローダーがCDSアーカイブのクラスを要求すると、VMは通常のクラスファイルパースおよび検証をスキップし、アーカイブのコピーをロードします。
- Custom class loaders: カスタムクラスローダが
ClassLoader::defineClass
を呼ぶと、アーカイブクラスとクラスファイルのマッチングを、クラスファイルデータのフィンガープリントでマッチングを試行します。もしマッチする場合、VMはクラスファイルのパースおよび検証をスキップし、アーカイブのコピーを直接ロードします。
Alternatives
複数のJVMプロセスが動的にロードするクラスの共有に共有メモリ領域を検討しましたが、共有のポテンシャルは低く*1実装困難なことが分かりました。
その代わりに、アプリケーションクラスデータの共有をstaticにしました。
- 'dump'のひと手間が追加。
- アプリケーションのJARファイルを更新すると再度dumpが必要。
本機能は既存のCDS上に構築するため、実装をシンプルにして、想定ユースケースにおいて高レートの共有を実現します。
Testing
互換性の保証とパフォーマンスを確認する網羅的なテストが必要です。
テストはすべてのサポートプラットフォームで実行します。ある種のプラットフォーム(特にWindows/x86)では、Address Space Layout Randomization (ASLR)が理由でJVMがアーカイブのマッピングが出来ずにテストが失敗する可能性があります。
Risks and Assumptions
AppCDSはJDK 8とJDK 9のOracle JDKで実装されています。本JEPではそのソースコードをオープンなリポジトリに移行し、一般利用可能にします。AppCDSはJDK 8とJDK 9で網羅的なテストをしているため、互換性と安定性のリスクは低いです。
*1:the sharing potential to be lower