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
cl4cds
cl4cds
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