JEP 310: Application Class-Data Sharing
Summary
To improve startup and footprint, extend the existing Class-Data Sharing ("CDS") feature to allow application classes to be placed in the shared archive.
Goals
-
Reduce footprint by sharing common class metadata across different Java processes.
-
Improve startup time.
-
Extend CDS to allow archived classes from the JDK's run-time image file (
$JAVA_HOME/lib/modules
) and the application class path to be loaded into the built-in platform and system class loaders. -
Extend CDS to allow archived classes to be loaded into custom class loaders.
Non-Goals
-
The shared-class archive storage format used in this implementation will not be standardized.
-
In this release, CDS cannot archive classes from user-defined modules (such as those specified in
--module-path
). We plan to add that support in a future release.
Success Metrics
This project will be considered successful if we can achieve (1) significant space saving in the memory used by Java class metadata across multiple JVM processes, and (2) significant startup time improvements.
For illustrative purposes:
-
We can save about 340MB of RAM for a Java EE app server that includes 6 JVM processes consuming a total of 13GB of RAM (~2GB of that is for class meta data).
-
We can improve the startup time of the JEdit benchmark by 20-30%.
-
We can reduce the RAM usage of the embedded Felix benchmark by 18% across 4 JVM processes.
These numbers reflect specific benchmarks and may not be generally applicable. The benefit of this work depends on the number of classes loaded by the supported class loaders as well as the heap usage of the application as a whole.
Description
Class-Data Sharing, introduced in JDK 5, allows a set of classes to be pre-processed into a shared archive file that can then be memory-mapped at runtime to reduce startup time. It can also reduce dynamic memory footprint when multiple JVMs share the same archive file.
Currently CDS only allows the bootstrap class loader to load archived classes. Application CDS ("AppCDS") extends CDS to allow the built-in system class loader (a.k.a., the "app class loader"), the built-in platform class loader, and custom class loaders to load archived classes.
Analysis of the memory usage of large-scale enterprise applications shows that such applications often load tens of thousands of classes into the application class loader. Applying AppCDS to these applications will result in memory savings of tens to hundreds of megabytes per JVM process.
Analysis of serverless cloud services shows that many of them load several thousand application classes at start-up. AppCDS can allow these services to start up quickly and improve the overall system response time.
Enabling AppCDS
By default, Class-Data Sharing is enabled only for the JVM's bootstrap class loader. Specify the -XX:+UseAppCDS
command-line option to enable class data sharing for the system class loader (a.k.a. "app class loader"), the platform class loader, and other user-defined class loaders.
Determining the classes to archive
An application may be packaged with a large number of classes but use only a fraction of them during normal operation. By archiving only the classes that are used, we can reduce the file storage size and runtime memory usage. To do this, first run the application normally with -Xshare:off
, and use the -XX:DumpLoadedClassList
command-line option to record all the classes that are loaded.
Note that -XX:DumpLoadedClassList
by default includes only the classes loaded by the bootstrap class loader. You should specify the -XX:+UseAppCDS
option so that classes loaded by the system class loader and platform class loader are also included. For example:
java -Xshare:off -XX:+UseAppCDS -XX:DumpLoadedClassList=hello.lst -cp hello.jar HelloWorld
Creating the AppCDS archive
To create the AppCDS archive, specify the -Xshare:dump -XX:+UseAppCDS
command-line options, pass the list of classes with the -XX:SharedClassListFile
option, and set the classpath to be the same as used by your application. You should also use the -XX:SharedArchiveFile
option to specify the name of the archive file to store the classes. Note that if -XX:SharedArchiveFile
is not specified then the archived classes will be stored into the JDK's installation directory, which is typically not what you want to do. For example:
$ java -Xshare:dump -XX:+UseAppCDS -XX:SharedClassListFile=hello.lst \
-XX:SharedArchiveFile=hello.jsa -cp hello.jar
Using the AppCDS archive
Once the AppCDS archive is created, you can use it when starting the application. Do this by specifying the -Xshare:on -XX:+UseAppCDS
command-line options, with the -XX:SharedArchiveFile
option to indicate the name of the archive file. For example:
$ java -Xshare:on -XX:+UseAppCDS -XX:SharedArchiveFile=hello.jsa \
-cp hello.jar HelloWorld
Classpath mismatch
The classpath used with -Xshare:dump
must be the same as, or be a prefix of, the classpath used with -Xshare:on
. Otherwise, the JVM will print an error message about the mismatched classpath and refuse to start. To analyze the mismatch, you can add -Xlog:class+path=info
to the application's command-line, and the JVM will print out detailed diagnostic information about what classpath is expected, and what classpath is actually used.
Using -Xshare:auto
{#Using--Xshare:auto}
AppCDS works by memory-mapping the contents of the archive at a fixed address. On some operating systems, especially when address space layout randomization (ASLR) is enabled, the memory-mapping operation may occassionally fail when the required address space is not available. If the -Xshare:on
option is specified, the JVM will treat this as an error condition and fail to start. To make your application more resilient in such situations, we recommend that the -Xshare:auto
option to be used instead. This way, when the JVM fails to memory-map the archive, it will disable AppCDS and continue to run the application normally.
Please note that -Xshare:auto
will also disable AppCDS if there's a classpath mismatch. Therefore, we recommend that you first test with -Xshare:on
to ensure there's no classpath mismatch, and then use -Xshare:auto
in the production environment.
Listing the Classes Loaded from the AppCDS Archive
To find out what classes have been loaded from the AppCDS archive, you can use the -Xlog:class+load=info
command-line option, which prints out the name of each loaded class, as well as from where the class is loaded. Classes loaded from the CDS archive will be printed as source: shared objects file
. For example:
$ 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: The HotSpot VM recognizes class-loading requests from the built-in platform and system class loaders. When these loaders request a class that exists in the CDS archive then the VM skips the usual class-file parsing and verification steps and loads the archived copied of the class.
-
Custom class loaders: When a custom class loader invokes
ClassLoader::defineClass
, the VM attempts to match the contents of the class file with an archived class by comparing fingerprints of the class-file data. If a match is found, the VM skips the class-file parsing and verification steps and directly loads the archived copy of the class.
Alternatives
We considered using a shared-memory region to share classes that are dynamically loaded by multiple live JVM processes, but we found the sharing potential to be lower and the implementation to be more difficult.
We have, instead, chosen to make the application class-data sharing more static:
-
An extra 'dump' step is required.
-
When the application's JAR files are updated, the dump step needs to be repeated.
This is built on top of the existing CDS infrastructure, so the implementation is simpler and we can achieve a higher ratio of sharing with our target use cases.
Testing
Extensive testing is needed to ensure compatibility and confirm performance benefits.
Testing should be performed on all supported platforms. On some platforms (especially Windows/x86) tests may fail if the JVM is unable to map the archive due to Address Space Layout Randomization (ASLR).
Risks and Assumptions
AppCDS was previously implemented in the Oracle JDK for JDK 8 and JDK 9. This JEP moves the source code to the open repository in order to make the feature generally available. Because AppCDS has been extensively tested in JDK 8 and JDK 9, the risk to compatibility and stability is low.