cl4cds (https://github.com/simonis/cl4cds) is a little tool which helps exploring the new Application Class Data Sharing (AppCDS) feature in OpenJDK 10. AppCDS allows sharing of application classes even if they get loaded by a custom class loaders, but unfortunately there’s currently no default tooling available to make this feature accessible to end users. That’s where cl4cds (which is an acronym for "class list for class data sharing") kicks in. It converts a class list obtained from running your application with -Xlog:class+load=debug to a format which can be passed to the VM as a parameter of the -XX:SharedClassListFile= option. This article documents the cl4cds tool but at the same time also describes the implementation and the benefits of the ovarall CDS/AppCDS features.

TL;DR

If you’re only interested in the cl4cds utility, you can use it as follows (tested with OpenJDK 10 and Tomcat 9):

$ export JAVA_HOME=JAVA_10_HOME (1)
$ export CATALINA_OPTS=-Xlog:class+load=debug:file=/tmp/tomcat.classtrace (2)
$ CATALINA_HOME/bin/catalina.sh start (3)
$ CATALINA_HOME/bin/catalina.sh stop (4)
$ JAVA_10_HOME/bin/java io.simonis.cl4cds /tmp/tomcat.classtrace /tmp/tomcat.cls
$ export CATALINA_OPTS="-Xshare:dump -XX:+UseAppCDS -XX:SharedClassListFile=/tmp/tomcat.cls -XX:+UnlockDiagnosticVMOptions -XX:SharedArchiveFile=/tmp/tomcat.jsa" (5)
$ CATALINA_HOME/bin/catalina.sh start (6)
$ export CATALINA_OPTS="-Xshare:on -XX:+UseAppCDS -XX:+UnlockDiagnosticVMOptions -XX:SharedArchiveFile=/tmp/tomcat.jsa" (7)
$ CATALINA_HOME/bin/catalina.sh start (8)
1 AppCDS only works with OpenJDK 10 and higher
2 Trace all the classes which get loaded into the file /tmp/tomcat.classtrace
3 Start Tomcat and run your application
4 Stop Tomcat
5 Set the options for creating a shared class archive in /tmp/tomcat.jsa (-XX:SharedArchiveFile is a diagnostic option so we have to enable it first by using -XX:+UnlockDiagnosticVMOptions)
6 Restart Tomcat to dump the shared class archive
7 Set the options for using the shared class archive from /tmp/tomcat.jsa
8 From now on, Tomcat will load available classes (both, system and application ones) from the shared archive if available.

The current cl4cds command line options are as follows:

io.simonis.cl4cds [<class-trace-file> [<class-list-file>]]

  <class-trace-file>: class trace obtained by running -Xlog:class+load=debug
                      if not specified read from <stdin>
  <class-list-file> : class list which can be passed to -XX:SharedClassListFile
                      if not specified written to <stdout>

  The following properties can be used to configure cl4cds:
    -Dio.simonis.cl4cds.debug=true :
       Print additional tracig to <stderr> (defaults to 'false')
    -Dio.simonis.cl4cds.dumpFromClassFile=true :
       Include classes into the output which are loaded from plain classfiles.
       This is currently not supported by OpenJDK 10 which can only dump
       classes from .jar files but may change eventually (defaults to 'false')

If you’re interested in the implementation details of CDS/AppCDS, their current limitations and their performance and memory characteristics please read on or watch my talk about Class Data Sharing (mp4, WebM/VP9, YouTube) in the Free Java DevRoom at FOSDEM 2018.

the following is work in progress!

Class Data Sharing

Class Data Sharing (CDS) is a feature to improve startup performance and reduce the memory footprint of the HotSpot JVM by storing the preprocessed metadata of system classes to disk and sharing them between virtual machines running on the same host. It was introduced as early as 2004 with the first release of Oracle’s Java 5 release and later became available in the first version of OpenJDK (i.e. jdk6). During the last years, this feature has been constantly extended and improved. Oracle JDK 9 introduced AppCDS as a commercial feature only, which additionally allows the caching and sharing of application classes, strings and symbols. This commercial feature will be open sourced and made freely available in OpenJDK 10 by JEP 310: Application Class-Data Sharing.

Starting with their Java SDK 6.0, IBM also started to support Class Data Sharing. They not only supported system class but also classes loaded by the application class loader (a.k.a. system class loader), classes loaded by custom class loaders and even ahead-of-time (AOT) compiled code (which was not shared between JVMs). While IBM J9’s CDS addresses similar problems like the HotSpot class data sharing feature in Oracle/OpenJDK, it is technically a completely independent implementation. Although it is much more mature and elaborate compared to the HotSpot implementation, J9’s CDS hasn’t attracted that much attention simply because Oracle/OpenJDK has been the predominant JVM in the past decade. But that might change with the open sourcing of the IBM J9 JVM within the Eclipse OpenJ9 project.

This article will only cover the HotSpot CDS functionality and implementation. If you’re interested in the J9/OpenJ9 implementation you may have a look at the latest documentation, watch the presentation about "OpenJ9: Under the hood of the next open source JVM" from Geekon 2017 / Krakow or Devoxx 2017 / Poland or simply download OpenJ9 and run java -Xshareclasses:help :wink:

Using CDS

In Oracle J2SE 5.0 the usage of CDS was quite restricted - the feature was only available in the Client VM when running with the Serial GC. Meanwhile, Oracle/OpenJDK 9 CDS also supports the G1, Serial, Parallel, and ParallelOld GCs with the Server VM. The following examples are all based on OpenJDK 9.

Before CDS can be used, the so called Shared Archive has to be created first:

$ java -Xshare:dump
Allocated shared space: 50577408 bytes at 0x0000000800000000
Loading classes to share ...
Loading classes to share: done.
Rewriting and linking classes ...
Rewriting and linking classes: done
Number of classes 1197
    instance classes   =  1183
    obj array classes  =     6
    type array classes =     8
Updating ConstMethods ... done.
Removing unshareable information ... done.
ro space:   5332520 [ 30.5% of total] out of  10485760 bytes [ 50.9% used] at 0x0000000800000000
rw space:   5630560 [ 32.2% of total] out of  10485760 bytes [ 53.7% used] at 0x0000000800a00000
md space:     98976 [  0.6% of total] out of   4194304 bytes [  2.4% used] at 0x0000000801400000
mc space:     34053 [  0.2% of total] out of    122880 bytes [ 27.7% used] at 0x0000000801800000
st space:     12288 [  0.1% of total] out of     12288 bytes [100.0% used] at 0x00000000fff00000
od space:   6363752 [ 36.4% of total] out of  20971520 bytes [ 30.3% used] at 0x000000080181e000
total   :  17472149 [100.0% of total] out of  46272512 bytes [ 37.8% used]

In this simplest form, the -Xshare:dump command will use a default class list JAVA_HOME/lib/classlist which was created at JDK build time and create the shared class archive under JAVA_HOME/lib/server/classes.jsa:

$ (cd JAVA_HOME && ls -o lib/classlist lib/server/classes.jsa)
-rw-rw-r-- 1 simonis    40580 Okt 23 19:06 lib/classlist
-r--r--r-- 1 simonis 17485824 Dez 30 11:39 lib/server/classes.jsa

JAVA_HOME/lib/classlist is a text file which contains the list of classes (one class per line, in internal form) which should be added to the shared class archive:

$ head -5 JAVA_HOME/lib/classlist
java/lang/Object
java/lang/String
java/io/Serializable
java/lang/Comparable
java/lang/CharSequence

As mentioned before, the classlist file is created at JDK build-time (controlled by the --enable-generate-classlist/--disable-generate-classlist flag which defaults to true on platforms which support CDS) by running a simple Java program called HelloClasslist (see GenerateLinkOptData.gmk) with the -XX:DumpLoadedClassList=<classlist_file> option to collect the system classes it uses. Of course, HelloClasslist is only a simple approximation for the amount of system classes a typical, small Java application will use.

We can now take a simple HelloCDS Java program and run it with -Xshare:on to take advantage of the shared class archive:

package io.simonis;

public class HelloCDS {
  public static void main(String[] args) {
    System.out.println("Hello CDS");
  }
}

-Xshare:on instructs to VM to use the shared class from the default location at JAVA_HOME/lib/server/classes.jsa. If the archive hasn’t been created or is corrupted, the VM will exit with an error:

$ rm -f JAVA_HOME/lib/server/classes.jsa
$ java -Xshare:on HelloCDS
An error has occurred while processing the shared archive file.
Specified shared archive not found.
Error occurred during initialization of VM
Unable to use shared archive.

We could instead use -Xshare:auto which behaves like -Xshare:on if the shared archive is available and automatically falls back to -Xshare:off if the shared archive can not be found or used. After recreating the archive, our program will run just fine, but how can we verify which classes get really loaded right from the shared class archive?

$ java -Xshare:on HelloCDS
Hello CDS

Here the class loading log comes in quite handy, because it not only reports which classes are being loaded, but also where they get loaded from in the source: section:

$ java -Xshare:on -Xlog:class+load io.simonis.HelloCDS
[0.011s][info][class,load] opened: /share/output-jdk9-dev-opt/images/jdk/lib/modules
[0.024s][info][class,load] java.lang.Object source: shared objects file
[0.024s][info][class,load] java.io.Serializable source: shared objects file
[0.024s][info][class,load] java.lang.Comparable source: shared objects file
...

In order to check which classes haven’t been loaded from the archive, we can grep for all log entries which don’t contain the term shared objects file:

$ java -Xshare:on -Xlog:class+load HelloCDS | grep --invert-match "shared objects file"
[0.014s][info][class,load] opened: /share/output-jdk9-dev-opt/images/jdk/lib/modules
[0,073s][info][class,load] java.util.ImmutableCollections$ListN source: jrt:/java.base
[0,079s][info][class,load] jdk.internal.module.ModuleHashes$Builder source: jrt:/java.base
[0,080s][info][class,load] jdk.internal.module.ModuleHashes$HashSupplier source: jrt:/java.base
[0,080s][info][class,load] jdk.internal.module.SystemModuleFinder$2 source: jrt:/java.base
[0,128s][info][class,load] jdk.internal.loader.URLClassPath$FileLoader source: jrt:/java.base
[0,140s][info][class,load] jdk.internal.loader.URLClassPath$FileLoader$1 source: jrt:/java.base
[0,149s][info][class,load] io.simonis.HelloCDS source: file:/FOSDEM2018/git/examples/bin/
Hello CDS

As we can see, there are just a few classes from the base module which still get loaded directly from the java runtime image (i.e. from the lib/modules file). Obviously they were not referenced or used by the HelloClasslist application which was used to generate the default class list under JAVA_HOME/lib/classlist. But we can of course generate a new, individual class list for our HelloCDS application, much in the same way the default class list was generated at build time (by using the -XX:DumpLoadedClassList=<classlist_file> option). Afterwards we use that class list (by using the -XX:SharedClassListFile=<classlist_file>) to generate a new, application specific shared archive. If we do not explicitly specify the location of the new archive file with the -XX:SharedArchiveFile=<classlist_file> option (which is a diagnostic option so we need -XX:+UnlockDiagnosticVMOptions as well) the default archive at JAVA_HOME/lib/server/classes.jsa will be silently overwritten.

$ java -XX:DumpLoadedClassList=/tmp/HelloCDS.cls io.simonis.HelloCDS
$ java -XX:SharedClassListFile=/tmp/HelloCDS.cls -XX:+UnlockDiagnosticVMOptions -XX:SharedArchiveFile=/tmp/HelloCDS.jsa -Xshare:dump
Allocated shared space: 50577408 bytes at 0x0000000800000000
Loading classes to share ...
Loading classes to share: done.
Rewriting and linking classes ...
Rewriting and linking classes: done
Number of classes 522 (1)
    instance classes   =   508
    obj array classes  =     6
    type array classes =     8
Updating ConstMethods ... done.
Removing unshareable information ... done.
ro space:   2498200 [ 31.5% of total] out of  10485760 bytes [ 23.8% used] at 0x0000000800000000
rw space:   2500208 [ 31.6% of total] out of  10485760 bytes [ 23.8% used] at 0x0000000800a00000
md space:     68760 [  0.9% of total] out of   4194304 bytes [  1.6% used] at 0x0000000801400000
mc space:     34053 [  0.4% of total] out of    122880 bytes [ 27.7% used] at 0x0000000801800000
st space:      8192 [  0.1% of total] out of      8192 bytes [100.0% used] at 0x00000000fff00000
od space:   2810480 [ 35.5% of total] out of  20971520 bytes [ 13.4% used] at 0x000000080181e000
total   :   7919893 [100.0% of total] out of  46268416 bytes [ 17.1% used]
1 The total number of classes dumped to the shared archive file

As you can see, the new archive contains fewer classes (522 compared to 1197 before). We can use the new archive by passing it to the VM with the -XX:SharedArchiveFile=<classlist_file> option:

$ java -Xshare:on -Xlog:class+load -XX:+UnlockDiagnosticVMOptions -XX:SharedArchiveFile=/tmp/HelloCDS.jsa io.simonis.HelloCDS | grep --invert-match "shared objects file"
[0.010s][info][class,load] opened: /share/output-jdk9-dev-opt/images/jdk/lib/modules
[0,176s][info][class,load] io.simonis.HelloCDS source: file:/FOSDEM2018/git/examples/bin/
Hello CDS

This time all the classes except our application class io.simonis.HelloCDS have been loaded from the shared archive!

CDS performance benefits

So let’s see if CDS makes any difference if it comes to start-up performance by using the time utility to measure the elapsed wall clock time (the output below actually shows the average of five runs in a row):

$ time -f "%e sec\n" java -Xshare:off -XX:+UnlockDiagnosticVMOptions -XX:SharedArchiveFile=/tmp/HelloCDS.jsa io.simonis.HelloCDS
Hello CDS
0.162 sec
$ time -f "%e sec\n" java -Xshare:on -XX:+UnlockDiagnosticVMOptions -XX:SharedArchiveFile=/tmp/HelloCDS.jsa io.simonis.HelloCDS
Hello CDS
0.148 sec

So it seems like CDS gives us about 9% better performance although we’ve actually measured the overall execution time here. We can do a little better by measuring the time it needs until our application class gets loaded (again showing the average of five consecutive runs):

$ time -f "%e sec\n" java -Xshare:off -XX:+UnlockDiagnosticVMOptions -XX:SharedArchiveFile=/tmp/HelloCDS.jsa -Xlog:class+load io.simonis.HelloCDS | grep HelloCDS
[0,164s][info][class,load] io.simonis.HelloCDS source: file:/FOSDEM2018/git/examples/bin/
0.178 sec
$ time -f "%e sec\n" java -Xshare:on -XX:+UnlockDiagnosticVMOptions -XX:SharedArchiveFile=/tmp/HelloCDS.jsa -Xlog:class+load io.simonis.HelloCDS | grep HelloCDS
[0,143s][info][class,load] io.simonis.HelloCDS source: file:/FOSDEM2018/git/examples/bin/
0.160 sec

Notice that the overall execution time has slightly increased because of the additional logging but the time until our HelloCDS class gets loaded is about 13% faster with CDS compared to the default run without CDS.

CDS memory savings

In order to gather some memory consumption statistics, we slightly extend our example program to read a byte from the standard input stream before exiting:

package io.simonis;

public class HelloCDS2 {
  public static void main(String[] args) throws java.io.IOException {
    System.out.println("Hello CDS");
    System.in.read();
  }
}

Now we can use various utilities to compare the consumed memory, but before that we create a new archive for our program:

$ java -XX:DumpLoadedClassList=/tmp/HelloCDS2.cls io.simonis.HelloCDS2 (1)
$ java -XX:SharedClassListFile=/tmp/HelloCDS2.cls -XX:+UnlockDiagnosticVMOptions -XX:SharedArchiveFile=/tmp/HelloCDS2.jsa -Xshare:dump (2)
$ java -Xshare:off -XX:+UnlockDiagnosticVMOptions -XX:SharedArchiveFile=/tmp/HelloCDS2.jsa -Xint io.simonis.HelloCDS2 (3) (4)
1 We create the class list of the loaded system classes..
2 ..and dump them to /tmp/HelloCDS2.jsa
3 We run the first test without CDS (i.e. -Xshare:off) ..
4 ..and in interpreter only mode (i.e. -Xint) because the JIT compilers will result in slightly different memory consumptions (because of different Code Cache layouts) due to timing variations.

First we try with the common Linux system tools like ps, top and pmap:

In order to get comparable results, we have to switch of Address Space Layout Randomization (ASLR) by executing sudo sh -c "echo 0 > /proc/sys/kernel/randomize_va_space".
$ top -n 1 -p `pgrep -f HelloCDS2`
  ...
  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
11772 simonis   20   0 4888828  28032  15172 S   0,0  0,3   0:00.18 java
$ ps -o pid,user,vsize,rss,comm `pgrep -f HelloCDS2`
   PID USER        VSZ   RSS COMMAND
 11772 simonis  4888828 28032 java
$ pmap `pgrep -f HelloCDS2` |  sed -n -e '2p;$p' (1)
          Address    Size   Rss   Pss Shared_Clean Shared_Dirty Private_Clean Private_Dirty Mapping
                  4888832 28484 25572         2956            0         12376         13152 KB
1 Magical sed command which outputs the second and the last line of its input

As we can see, ps and top agree on the same values for the mapped virtual memory (i.e. 4888828 KB) and the amount of memory which is really committed to RAM (i.e. the so called Residetn Set Size or RSS, 28032 KB). pmap reports slightly higher values (see ps man page) but is known to provide the most accurate information. Moreover, pmap also details the RSS into shared and private memory which will be important for our further investigations. A description of the various values reported can be found in this nice, graphical pmap cheat sheet or directly from the Linux Kernel proc file system documentation.

The SIZE and RSS fields don’t count some parts of a process including the page tables, kernel stack, struct thread_info, and struct task_struct. This is usually at least 20 KiB of memory that is always resident. SIZE is the virtual size of the process (code+data+stack).
— Linux man page
ps(1)

Now we start a second instance of our application to see how the shared memory consumption of the two processes changes:

$ java -Xshare:off -XX:+UnlockDiagnosticVMOptions -XX:SharedArchiveFile=/tmp/HelloCDS2.jsa -Xint io.simonis.HelloCDS2
$ pmap `pgrep -f HelloCDS2 | head -1` |  sed -n -e '2p;$p' (1)
         Address    Size   Rss   Pss Shared_Clean Shared_Dirty Private_Clean Private_Dirty Mapping
                 4888832 28484 19396        15304            0            28         13152 KB
$ pmap `pgrep -f HelloCDS2 | tail -1` |  sed -n -e '2p;$p' (2)
         Address    Size   Rss   Pss Shared_Clean Shared_Dirty Private_Clean Private_Dirty Mapping
                 4888832 28484 19396        15304            0             0         13180 KB
1 Get the pmap statistics of the first process one more time (assumes that PIDs are assigned incrementally)
2 Get the pmap statistics of the second process (assumes that PIDs are assigned incrementally)

After the second instance has been started, neither the virtual nor the committed memory consumption of the first process has changed. Furthermore the second process has the exact same memory footprint like the first one. However, after the start of the second process, we can observe that the amount of shared memory of process one has increased from 2956 KB to 15304 KB which leads to a decrease in the process' Proportional Set Size (PSS) from 25572 KB down to 19396 KB.

The "proportional set size" (PSS) of a process is the count of pages it has in memory, where each page is divided by the number of processes sharing it. So if a process has 1000 pages all to itself, and 1000 shared with one other process, its PSS will be 1500. Note that even a page which is part of a MAP_SHARED mapping, but has only a single pte mapped, i.e. is currently used by only one process, is accounted as private and not as shared.
— www.kernel.org
T H E /proc F I L E S Y S T E M

For the Java VM, the read-only parts of the loaded shared libraries (i.e. libjvm.so) can be shared between all the VM instances running at the same time. This explains why, taking together, the two VM’s consume less memory (i.e. have a smaller memory footprint) than the simple sum of their single resident set sizes when running alone. Notice that even a single instance has a PSS value which is smaller than the process' RSS value, because it uses commom shared libraries (e.g. libc.so) which are already mapped into the memory by other processes.

Now lets see how the situation changes when we use CDS:

$ java -Xshare:on -XX:+UnlockDiagnosticVMOptions -XX:SharedArchiveFile=/tmp/HelloCDS2.jsa -Xint io.simonis.HelloCDS2 (1)
$ pmap `pgrep -f HelloCDS2` | sed -n -e '2p;$p'
         Address    Size   Rss   Pss Shared_Clean Shared_Dirty Private_Clean Private_Dirty Mapping
                 4896596 32888 29991         2928            0         18632         11328 KB
$ java -Xshare:on -XX:+UnlockDiagnosticVMOptions -XX:SharedArchiveFile=/tmp/HelloCDS2.jsa -Xint io.simonis.HelloCDS2 (2)
$ pmap `pgrep -f HelloCDS2 | head -1` |  sed -n -e '2p;$p' (3)
         Address    Size   Rss   Pss Shared_Clean Shared_Dirty Private_Clean Private_Dirty Mapping
                 4896596 32888 20672        21560            0            32         11296 KB (5)
$ pmap `pgrep -f HelloCDS2 | tail -1` |  sed -n -e '2p;$p' (4)
         Address    Size   Rss   Pss Shared_Clean Shared_Dirty Private_Clean Private_Dirty Mapping
                 4896596 32888 20672        21560            0            28         11300 KB (6)
$ kill `pgrep -f HelloCDS2 | tail -1` (7)
$ pmap `pgrep -f HelloCDS2` |  sed -n -e '2p;$p'
         Address    Size   Rss   Pss Shared_Clean Shared_Dirty Private_Clean Private_Dirty Mapping
                 4896596 32888 29991         2928            0         18664         11296 KB (8)
1 Turn on Class Data Sharing (i.e. -Xshare:on)
2 Now start a second instance of io.simonis.HelloCDS2
3 Get the pmap statistics of the first process one more time
4 Get the pmap statistics of the second process
5 The Size/RSS values are still the same, but the amount of shared memory increases from 2928 KB to 21560 KB
6 The Size/RSS values of the second process are exactly the same like for the first process
7 Kill the second process..
8 ..and run pmap on the first process one more time (the amount of shared memory drops back to 2928 KB)

The first thing we notice is that both, the RSS (32888 vs. 28484 KB) and the PSS (29991 vs. 25572 KB) values are slightly higher compared to the non-CDS case. On the other hand, the PSS value drops more significantly (from 29991 to 20672 vs. from 25572 to 19396) in the CDS case after we start the second VM. The first observation can be explained by looking at the output of the -Xlog:gc+heap+exit output which prints some Heap and Metaspace statistics at VM exit:

$ java -Xlog:gc+heap+exit -Xshare:off -XX:+UnlockDiagnosticVMOptions -XX:SharedArchiveFile=/tmp/HelloCDS2.jsa -Xint io.simonis.HelloCDS2
Hello CDS

[735,797s][info][gc,heap,exit] Heap
[735,797s][info][gc,heap,exit]  garbage-first heap   total 8192K, used 531K [0x0000000083200000, 0x0000000100000000)
[735,798s][info][gc,heap,exit]   region size 1024K, 1 young (1024K), 0 survivors (0K)
[735,798s][info][gc,heap,exit]  Metaspace       used 3550K, capacity 4486K, committed 4864K, reserved 1056768K
[735,798s][info][gc,heap,exit]   class space    used 312K, capacity 386K, committed 512K, reserved 1048576K

$ java -Xlog:gc+heap+exit -Xshare:on  -XX:+UnlockDiagnosticVMOptions -XX:SharedArchiveFile=/tmp/HelloCDS2.jsa -Xint io.simonis.HelloCDS2
Hello CDS

[288,178s][info][gc,heap,exit] Heap
[288,179s][info][gc,heap,exit]  garbage-first heap   total 10240K, used 625K [0x0000000083200000, 0x0000000100000000)
[288,179s][info][gc,heap,exit]   region size 1024K, 1 young (1024K), 0 survivors (0K)
[288,179s][info][gc,heap,exit]  Metaspace       used 4K, capacity 4486K, committed 4864K, reserved 1056768K
[288,179s][info][gc,heap,exit]   class space    used 3K, capacity 386K, committed 512K, reserved 1048576K

We see that the Java heap usage is about 2 MB higher with CDS (10240 vs. 8192K KB). We also see that in the CDS case we only use 4 KB Meta- and 3 KB Classspace (compared to 3550 and 312 KB in the non-CDS case) because with CDS the classes are used directly from the CDS archive. Unfortunately, the VM still commits the exact same, minimal amount of Meta- and Classspace (4864 and 512 KB).

This observation can be confirmed by looking at the output of the VM.native_memory diagnostic command which details the various native memory consumers from within the VM if the VM was started with the -XX:NativeMemoryTracking=summary option:


CDS summary

Finally, it should be mentioned that the each of the various -Xshare options there exists a corresponding extended -XX: option as indicated in the following table:

Short Form Long Form

-Xshare:dump

-XX:+DumpSharedSpaces (implies -Xint)

-Xshare:on

-XX:+UseSharedSpaces -XX:+RequireSharedSpaces

-Xshare:auto

-XX:+UseSharedSpaces -XX:-RequireSharedSpaces

-Xshare:off

-XX:-UseSharedSpaces -XX:-RequireSharedSpaces

Colophon

Rendered with AsciiDoctor version 1.5.6.1