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.HelloCDS source: file:/examples/bin/
HelloCDS
$ java -Xshare:on -Xlog:class+load io.simonis.HelloCDS \
| grep "shared objects file" | wc -l
477
$ java -Xshare:on -Xlog:class+load io.simonis.HelloCDS \
| grep -v "shared objects file" | wc -l
5
$ /usr/bin/time -f "%e sec\n" java -Xshare:off io.simonis.HelloCDS
Hello CDS
0.162 sec
$ /usr/bin/time -f "%e sec\n" java -Xshare:on io.simonis.HelloCDS
Hello CDS
0.142 sec
About 13% (Java 10) / 22% (Java 11) overall performance improvement
$ java -Xshare:off -Xlog:class+load io.simonis.HelloCDS | grep HelloCDS
[0,159s][class,load] io.simonis.HelloCDS source: file:/examples/bin
$ java -Xshare:on -Xlog:class+load io.simonis.HelloCDS | grep HelloCDS
[0,136s][class,load] io.simonis.HelloCDS source: file:/examples/bin
Application class loads about 15% (Java 10) / 23% (Java 11) faster
$ export VERIFY_JRUBY=1
$ JAVA_OPTS="-Xshare:on -Xlog:class+load:file=jruby_cds.classtrace" \
jruby --dev -e 1
$ wc -l jruby.classtrace
6621 jruby.classtrace
$ grep "shared objects file" jruby.classtrace | wc -l
1008
$ JAVA_OPTS="-XX:DumpLoadedClassList=jruby_cds.cls" \
jruby --dev -e 1
$ wc -l jruby_cds.cls
1480 jruby_cds.cls
$ JAVA_OPTS="-XX:DumpLoadedClassList=jruby_appcds.cls -XX:+UseAppCDS" \
jruby --dev -e 1
$ wc -l jruby_appcds.cls
6504 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 \
-Xlog:class+load:file=jruby_appcds.clstrace" \
-XX:+UnlockDiagnosticVMOptions \
-XX:SharedArchiveFile=jruby_appcds.jsa \
jruby --dev -e 1
$ wc -l jruby_appcds.clstrace
6591 jruby_appcds.clstrace
$ grep "shared objects " jruby_appcds.clstrace | wc -l
6447
$ 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!!!
$ JAVA_OPTS="\
\
-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" \
\
\
/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=..." catalina.sh start
Nr. of shared classes | Total nr. of classes | |
---|---|---|
No CDS | - | 12.644 |
CDS (default archive) | 1.156 | 12.644 |
CDS (custom archive) | 3.261 | 12.644 |
CDS + AppCDS | 3.520 | 12.644 |
-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
java/lang/Object id: 1
...
org/apache/catalina/Server id: 9 super: 1 interfaces: 5 source: catalina.jar
-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 -l tomcat_cl4cds.clstrace
12644 tomcat_cl4cds.clstrace
$ grep "shared objects " tomcat_cl4cds.clstrace | wc -l
9380
SharedArchiveConfigFile
file from thejcmd <pid> VM.stringtable -verbose
andjcmd <pid> VM.symboltable -verbose
output
SharedArchiveConfigFile
$ 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
No CDS | CDS | AppCDS | CDS & AOT | Speedup | |
---|---|---|---|---|---|
OpenJDK 11 | 3.6s | 3.5s | - | 3% | |
OpenJDK 11 | 3.6s | - | 2.6s | - | 28% |
OpenJ9 9 | 6.3s | - | 6.2s | - | 2% |
OpenJ9 9 | 6.3s | - | - | 4.9 | 23% |