Volker Simonis, SAP / volker.simonis@gmail.com
              
$ java -Xshare:dump
Loading classes to share ...   // from JAVA_HOME/lib/classlist
total    :  18.422.144 [100.0% ] // to JAVA_HOME/lib/server/classes.jsa
$ java -Xshare:on io.simonis.HelloCDS
HelloCDS
$ java -Xshare:on -Xlog:class+load io.simonis.HelloCDS
[class,load] java.lang.Object source: shared objects file
...
[class,load] j.i.l.URLClassPath$FileLoader source: jrt:/java.base
...
[class,load] io.simonis.HelloCDS2 source: file:/examples/bin/
HelloCDS
$ java -Xshare:on -Xlog:class+load io.simonis.HelloCDS \
      | grep "shared objects file" | wc
    477    2862   40977
$ java -Xshare:on -Xlog:class+load io.simonis.HelloCDS \
      | grep -v "shared objects file" | wc
      5      17     424
              
            
          
              
$ time -f "%e sec\n" java -Xshare:off io.simonis.HelloCDS
Hello CDS
0.162 sec
$ time -f "%e sec\n" java -Xshare:on  io.simonis.HelloCDS          
Hello CDS
0.148 sec
              
            
            About 9% overall performance improvement
              
$ java -Xshare:off -Xlog:class+load io.simonis.HelloCDS
[0,164s][class,load] io.simonis.HelloCDS source: file:/examples/bin
$ java -Xshare:on  -Xlog:class+load io.simonis.HelloCDS
[0,143s][class,load] io.simonis.HelloCDS source: file:/examples/bin
              
            
            Application class loads about 13% faster
              
$ export VERIFY_JRUBY=1
$ JAVA_OPTS="-Xshare:on \
             -Xlog:class+load:file=jruby_cds.classtrace" \
  jruby --dev -e 1
$ wc jruby.classtrace
  6621   28511 806148 jruby.classtrace
$ grep "shared objects file" jruby.classtrace | wc
   1008    6048  89449
$ JAVA_OPTS="-XX:DumpLoadedClassList=jruby_cds.cls" \
  jruby --dev -e 1
$ wc jruby_cds.cls
   1480   1480 51716 jruby_cds.cls
$ JAVA_OPTS="-XX:DumpLoadedClassList=jruby_appcds.cls \
                 -XX:+UseAppCDS" \
  jruby --dev -e 1
$ wc jruby_appcds.cls
   6504   6504 262466 jruby_appcds.cls
              
            
          
              
$ JAVA_OPTS="-Xshare:dump -XX:+UseAppCDS \
             -XX:SharedClassListFile=jruby_appcds.cls \
             -XX:+UnlockDiagnosticVMOptions \
             -XX:SharedArchiveFile=jruby_appcds.jsa" \
  jruby --dev -e 1
$ ll jruby_appcds.jsa
-r--r----- 58.994.688 Mär  3 23:01 jruby_appcds.jsa
$ JAVA_OPTS="-Xshare:on -XX:+UseAppCDS \
             -XX:+UnlockDiagnosticVMOptions \
             -XX:SharedArchiveFile=jruby_appcds.jsa \
             -Xlog:class+load:file=jruby_appcds.clstrace" \
  jruby --dev -e 1
$ wc jruby_appcds.clstrace
  6591   39257 630637 jruby_appcds.clstrace
$ grep "shared objects " jruby_appcds.clstrace | wc
   6447   38682  615284
              
            
          
              
$ JAVA_OPTS="-Xshare:on -XX:+UseAppCDS \
             -XX:+UnlockDiagnosticVMOptions \
             -XX:SharedArchiveFile=/tmp/jruby_appcds.jsa" \
  /usr/bin/time -f "%e sec\n" ./bin/jruby --dev -e 1
2.02 sec
$ JAVA_OPTS="-Xshare:off -XX:+UseAppCDS \
             -XX:+UnlockDiagnosticVMOptions \
             -XX:SharedArchiveFile=/tmp/jruby_appcds.jsa" \
  /usr/bin/time -f "%e sec\n" ./bin/jruby --dev -e 1
3.05 sec
              
            
            About 30% startup performance improvement!!!
              
$ CATALINA_OPTS="-Xshare:on \
                 -Xlog:class+load:file=/tmp/tomcat.classtrace" \
  catalina.sh start
$ wc /tmp/tomcat.classtrace
  12644   50575 2075264 /tmp/tomcat.classtrace
$ grep "shared objects file" /tmp/tomcat.classtrace | wc
   1156    6936  103052
$ CATALINA_OPTS="-XX:DumpLoadedClassList=/tmp/tomcat.cls" \
  catalina.sh start
$ wc /tmp/tomcat.cls
   3261   3261 125647 /tmp/tomcat.cls
$ CATALINA_OPTS="-XX:DumpLoadedClassList=/tmp/tomcat_appcds.cls \
                 -XX:+UseAppCDS" \
  catalina.sh start
$ wc /tmp/tomcat_appcds.cls
   3520   3520 133431 /tmp/tomcat_appcds.cls
              
            
          
              
$ CATALINA_OPTS="-Xshare:dump -XX:+UseAppCDS \
                 -XX:SharedClassListFile=/tmp/tomcat_appcds.cls \
                 -XX:+UnlockDiagnosticVMOptions \
                 -XX:SharedArchiveFile=/tmp/tomcat_appcds.jsa" \
  catalina.sh start
$ ll /tmp/tomcat_appcds.jsa
-r--r----- 49.979.392 Feb  2 23:57 /tmp/tomcat_appcds.jsa
$ CATALINA_OPTS="-Xshare:on -XX:+UseAppCDS \
                 -XX:+UnlockDiagnosticVMOptions \
                 -XX:SharedArchiveFile=/tmp/tomcat_appcds.jsa \
                 -Xlog:class+load:file=/tmp/tomcat_appcds.clstrace" \
  catalina.sh start
$ wc /tmp/tomcat_appcds.clstrace
  12645   57615 2088947 /tmp/tomcat_appcds.clstrace
$ grep "shared objects " /tmp/tomcat_appcds.clstrace | wc
   3518   21108  327511
              
            
          -XX:+UseAppCDS-XX:DumpLoadedClassList=.. -XX:+UseAppCDS -XX:DumpLoadedClassList=... creates a trivial class list:
                  
$ cat /tmp/tomcat_appcds.cls
java/lang/Object
java/lang/String                                          
...
org/apache/catalina/startup/Bootstrap
                  
                
              
                  
CLASSNAME [ ID ]?
CLASSNAME ID super: ID [ interface: [ ID ]+ ]? source: URL
                  
                
              -Xlog:class+load=debug has all the information we need:
                  
$ CATALINA_OPTS="-Xlog:class+load=debug" catalina.sh start
[info ] java.lang.Object source: jrt:/java.base
[debug]  klass: 0x100000eb0 super: 0x000000000 loader: [NULL class loader]
....
[info ] java.sql.Timestamp source: jrt:/java.sql
[debug]  klass: 0x100096c30 super: 0x100091a00 \
         loader: [0xff0172600 a 'ClassLoaders$PlatformClassLoader']
....
[info ] org.apache.catalina.Server source: file:catalina.jar
[debug]  klass: 0x1000e6410 super: 0x100000eb0 interfaces: 0x1000e6238 \
         loader: [0xff0310fb0 a 'java/net/URLClassLoader']
                  
                
              
                  
java/lang/Object           id: 0x100000eb0
java/sql/Timestamp         id: 0x100096c30
org/apache/catalina/Server id: 0x1000e6410 super: 0x100000eb0 \        
                           interfaces: 0x1000e6238 source: catalina.jar
                  
                
              cl4cdscl4cds converts a class log into a CDS class list:
                
                  
$ CATALINA_OPTS="-Xlog:class+load=debug:file=tomcat_dbg.clstrace" \
  catalina.sh start
$ java io.simonis.cl4cds tomcat_dbg.clstrace tomcat_cl4cds.cls
$ CATALINA_OPTS="-Xshare:dump -XX:+UseAppCDS \
                 -XX:SharedClassListFile=tomcat_cl4cds.cls \
                 -XX:+UnlockDiagnosticVMOptions \
                 -XX:SharedArchiveFile=tomcat_cl4cds.jsa" \
  catalina.sh start
$ ll tomcat_cl4cds.jsa
-r--r----- 1 102.305.792 Feb  3 01:48 tomcat_cl4cds.jsa
$ CATALINA_OPTS="-Xshare:on -XX:+UseAppCDS \
                 -XX:+UnlockDiagnosticVMOptions \
                 -XX:SharedArchiveFile=tomcat_cl4cds.jsa \
                 -Xlog:class+load:file=tomcat_cl4cds.clstrace" \
  catalina.sh start
$ wc tomcat_cl4cds.clstrace
  12644   69335 1531203 tomcat_cl4cds.clstrace
$ grep "shared objects " tomcat_cl4cds.clstrace | wc
   9380   56280  963418
                  
                
          SharedArchiveConfigFile file from thejcmd <pid> VM.stringtable -verbose andjcmd <pid> VM.symboltable -verbose outputSharedArchiveConfigFile
              
$ jcmd `pgrep -f tomcat` VM.stringtable -verbose                   
1619:
VERSION: 1.1
23: java.nio.file.attribute                            
16: javax.swing.plaf                                   
...                                                    
$ jcmd `pgrep -f tomcat` VM.symboltable -verbose
1619:
VERSION: 1.0
34 2: Ljava/util/List<Ljava/net/Proxy;>;               
9 -1: java.net.                                        
...                                                    
              
            
            
              
$ vi string_symbol.cfg
VERSION: 1.0                                                       
@SECTION: String
<output of jcmd VM.stringtable>
@SECTION: Symbol
<output of jcmd VM.symboltable>
              
            
          SharedArchiveConfigFile
              
$ CATALINA_OPTS="-Xshare:dump -XX:+UseAppCDS \
                 -XX:SharedClassListFile=tomcat_cl4cds.cls \
                 -XX:+UnlockDiagnosticVMOptions \
                 -XX:SharedArchiveFile=tomcat_cl4cds.jsa" \
  catalina.sh start
$ ll tomcat_cl4cds.jsa
-r--r----- 1 102.305.792 Feb  3 01:48 tomcat_cl4cds.jsa
$ CATALINA_OPTS="-Xshare:dump -XX:+UseAppCDS \
                 -XX:SharedClassListFile=tomcat_cl4cds.cls \
                 -XX:SharedArchiveConfigFile=string_symbol.cfg \
                 -XX:+UnlockDiagnosticVMOptions \
                 -XX:SharedArchiveFile=tomcat_cl4cds.jsa" \
  catalina.sh start
$ ll tomcat_cl4cds.jsa
-r--r----- 1 106.323.968 Mär  2 13:15 tomcat_cl4cds.jsa
              
            
          /opt/tomcat_cl4cds.jsa`sudo sh -c "echo 0 > /proc/sys/kernel/randomize_va_space"`)CATALINA_OPTS="-Xint -Xmx64m -Xms64m -XX:+UseG1GC -Djava.security.egd=file:/dev/./urandom
               -XX:+UseAppCDS -XX:+UnlockDiagnosticVMOptions -XX:SharedArchiveFile=/opt/tomcat_cl4cds.jsa" catalina.sh start
            
              
$ java -Xshare:dump
Allocated shared space: 3221225472 bytes at 0x0000000800000000
Loading classes to share ... // from JAVA_HOME/lib/classlist
Rewriting and linking classes ...  // Verification, ...
Number of classes 1240
Removing unshareable information ... done.
Relocating embedded pointers ...
Dumping symbol table ...                                
Dumping String objects to closed archive heap region ...
Dumping objects to open archive heap region ...
Removing java_mirror ... done.  // java.lang.Class<?>
mc  space:     21832 [  0,1% ] ... at 0x0000000800000000
rw  space:   4093816 [ 22,2% ] ... at 0x0000000800006000
ro  space:   7313320 [ 39,7% ] ... at 0x00000008003ee000
md  space:      6352 [  0,0% ] ... at 0x0000000800ae8000
od  space:   6462536 [ 35,1% ] ... at 0x0000000800aea000
st0 space:    458752 [  2,5% ] ... at 0x00000000fff00000
oa0 space:     65536 [  0,4% ] ... at 0x00000000ffe00000
total    :  18422144 [100.0% ] 
              
            
          
              
$ docker run -p 8080:8080 --rm -m 500m cds_demo_ojdk
$ pmap -XX 1508
1508:   /opt/jdk/bin/java ... org.apache.catalina.startup.Bootstrap start
  Address Perm    Size    Rss Shared_Clean Private_Clean Private_Dirty Mapping
 00400000 r-xp       4      4            0             4             0 java
 fc000000 rw-p   52224  52224            0             0         52224 // [Java heap]
 ff300000 rw-p     172    172            0            24           148 tomcat_cl4cds.jsa
 ff400000 rw-p     408    408            0           408             0 tomcat_cl4cds.jsa
 ff500000 rw-p    3072   3072            0          3072             0 tomcat_cl4cds.jsa
800000000 rwxp      16     16            0             0            16 tomcat_cl4cds.jsa
800004000 rw-p   22340  22340            0          1640         20700 tomcat_cl4cds.jsa
8015d5000 r--p   39320  39320            0         39320             0 tomcat_cl4cds.jsa
803c3b000 rw-p       8      8            0             0             8 tomcat_cl4cds.jsa
803c3d000 r--p   35840  35840            0         35840             0 tomcat_cl4cds.jsa
              
            
          
              
$ docker run -p 8090:8080 --rm -m 500m cds_demo_ojdk
$ pmap -XX 1508
1508:   /opt/jdk/bin/java ... org.apache.catalina.startup.Bootstrap start
  Address Perm    Size    Rss Shared_Clean Private_Clean Private_Dirty Mapping
 00400000 r-xp       4      4            4             0             0 java
 fc000000 rw-p   52224  52224            0             0         52224 // [Java heap]
 ff300000 rw-p     172    172           24             0           148 tomcat_cl4cds.jsa
 ff400000 rw-p     408    408          408             0             0 tomcat_cl4cds.jsa
 ff500000 rw-p    3072   3072         3072             0             0 tomcat_cl4cds.jsa
800000000 rwxp      16     16            0             0            16 tomcat_cl4cds.jsa
800004000 rw-p   22340  22340         1640             0         20700 tomcat_cl4cds.jsa
8015d5000 r--p   39320  39320        39320             0             0 tomcat_cl4cds.jsa
803c3b000 rw-p       8      8            0             0             8 tomcat_cl4cds.jsa
803c3d000 r--p   35840  35840        35840             0             0 tomcat_cl4cds.jsa
              
            
          | -Xshare:dump | -Xshare:{on,auto} | |
|---|---|---|
| --module-path | Allow | Allow | 
| --add-modules | Allow | Allow | 
| --module | Allow | Allow | 
| --limit-modules | Disallow (exit if specified) | Allow (disable CDS) | 
| --patch-module | Disallow (exit if specified) | Allow (disable CDS) | 
| --upgrade-module-path | Disallow (exit if specified) | Allow (disable CDS) | 
For more details see module-path-design.pdf
-XX:+UseAppCDS will be enabled by defaultSharedClassListFile will be written to the archive at dump time-XX:SharedArchiveFile becomes a product flag
                -XX:+UnlockDiagnosticVMOptions any moreURLClassLoader work out of the box-Xshareclasses, ..)
              
$ CATALINA_OPTS="-Xscmx128m -Xshareclasses:cacheDir=/tmp/tomcat,name=tomcat,verbose" \
  catalina.sh start
[-Xshareclasses persistent cache enabled]
JVMSHRC236I Created shared classes persistent cache tomcat
JVMSHRC246I Attached shared classes persistent cache tomcat
JVMSHRC168I Total shared class bytes read=3738038. Total bytes stored=47196956
$ ls -l /tmp/tomcat
-rw-r----- 1 simonis simonis 134217728 Feb 23 17:44 C290M5F1A64P_tomcat_G35
$ java -Xshareclasses:cacheDir=/tmp/tomcat,name=tomcat,printStats
Current statistics for cache "tomcat":
cache size                           = 134_217_120
free bytes                           =  80_991_164
ROMClass bytes                       =  28_017_248
AOT bytes                            =  13_330_160
JIT data bytes                       =      99_072
Data bytes                           =     363_936
Metadata bytes                       =     70_8596
# ROMClasses                         =      11_589
# AOT Methods                        =       6_329
Cache is 39% full
              
            
          /opt/tomcat_cl4cds.jsa & /opt/tomcat/C290M5F1A64P_tomcat_G35`sudo sh -c "echo 0 > /proc/sys/kernel/randomize_va_space"`)CATALINA_OPTS="-Xint -Xmx64m -Xms64m -XX:+UseG1GC -Djava.security.egd=file:/dev/./urandom
               -XX:+UseAppCDS -XX:+UnlockDiagnosticVMOptions -XX:SharedArchiveFile=/opt/tomcat_cl4cds.jsa" catalina.sh start
              CATALINA_OPTS="-Xint -Xmx64m -Xms64m -Djava.security.egd=file:/dev/./urandom
               -Xshareclasses:cacheDir=/opt/tomcat,name=tomcat,noaot,nojitdata -Xnoaot -Xnojit" catalina.sh start