To improve startup and footprint, extend the existing Class-Data Sharing ("CDS") feature to allow application classes to be placed in the shared archive.
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.
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.
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.
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.
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
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.
-XX:DumpLoadedClassList by default includes only the
classes loaded by the bootstrap class loader. You should specify the
-XX:+AppCDS 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
-XX:+UseAppCDS command-line options, pass the list of classes with
-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.
$ 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
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
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
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.
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
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.
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.
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.