When Java executes a program it read in the jar file, breaks it into the individual classes, converts the byte codes into instructions, and when executing it may replace instructions with more efficient instructions (Jitting). It can also convert the byte codes into instructions ahead of time, so called Ahead Of Time (AOT) compilation.
With shared classes, the converted byte codes, any Jitted code, and any AOT code can be saved in a data space.
- When the java program runs a second time, it can reuse the data in the dataspace, avoid the overhead of the reading the jar file from the file system, and coverting the byte codes into instructions.
- The data space can be hardened to a file, and restored to a data space, so can be used across system IPLs.
Using this, it reduced the start-up time of my program by over 20 seconds on my slow zPDT system. The default size of the cache is 16MB – one of my applications needed 100 MB, so most of the benefits of he shared classes could not be exploited if the defaults were used.
This blog post describes more information about this, and what tuning you can do.
You have to use the same level of Java to display information, as used by the program. For example
export PATH="/usr/lpp/java/new/J8.0_64/bin:$PATH" /usr/lpp/java/new/J8.0_64/bin/java -Xshareclasses:cacheDir=/tmp,printStats,cache=rseapi
If the levels are different it may just report JVMSHRC005I No shared class caches available.
Issuing commands to manage the shared classes cache
What commands are there ?
The command
/usr/lpp/java/J17.0_64/bin/java -Xshareclasses:help
gives 100 lines of help including the syntax.
This help text includes
Related command line options:
-Xscmx<x> set size (or soft max size if option -XX:SharedCacheHardLimit= is present)
of new shared class cache to <x>
-Xscdmx<x> set size of shared class cache debug attribute area to <x>
-Xscminaot<x> set minimum shared classes cache space reserved for AOT data to <x>
-Xscmaxaot<x> set maximum shared classes cache space allowed for AOT data to <x>
-Xscminjitdata<x> set minimum shared classes cache space reserved for JIT data to <x>
-Xscmaxjitdata<x> set maximum shared classes cache space allowed for JIT data to <x>
-Xzero:nosharebootzip do not share bootstrap jar entry caches in the shared class cache
-XX:SharedCacheHardLimit=<x> set size of new shared class cache to <x>
-XX:ShareClassesEnableBCI create shared class cache with support for byte-code instrumentation
-XX:ShareClassesDisableBCI create shared class cache without support for byte-code instrumentation
-XX:+ShareAnonymousClasses enable storing and finding anonymous classes in the shared class cache
-XX:-ShareAnonymousClasses disable storing and finding anonymous classes in the shared class cache
-XX:+ShareUnsafeClasses enable storing and finding non-anonymous unsafe classes in the shared class cache
-XX:-ShareUnsafeClasses disable storing and finding non-anonymous unsafe classes in the shared class cache
-XX:+UseGCStartupHints enable storing and finding GC startup hints in the shared class cache
-XX:-UseGCStartupHints disable storing and finding GC startup hints in the shared class cache
Commands to manage the shared classes cache are issued like
java -Xshareclasses:cacheDir=/tmp,name=client6,printStats
which can be done using JCL
// SET V=’listAllCaches’
// SET V=’printStats’
// SET C=’/tmp’
// SET N=’client6′
//S1 EXEC PGM=BPXBATCH,REGION=0M,
// PARM=’SH java -Xshareclasses:cacheDir=&C,name=&N,verbose,&V’
//STDERR DD SYSOUT=*
//STDOUT DD SYSOUT=*
Enabling share classes
You specify -Xsharedclasses information as a parameter to the program, for example in the command line or in a jvm properties file.
To use the shared classes capability you have to specify all of the parameters on one line, like
-Xshareclasses:verbose,name=client6,cacheDirPerm=0777,cacheDir=/tmp
Having it like
-Xshareclasses:name=client6,,cacheDirPerm=0777,cacheDir=/tmp
-Xshareclass:verbose
means the name, etc all take their defaults. Only shareclass:verbose would be used.
Changing share classes parameters
You can have more than one cache; you specify a name. You specify a directory were an image is stored when the cache is hardened to disk.
Some of the options like name= and cacheDir= are picked up when the JVM starts, Other parameters like cacheDirPerm are only used when the cache is (re-)created.
You can delete the cache in two ways.
Delete the cache from your your Java program
When you are playing around, you can add reset to the end of the -Xshareclasses string to caused the cache to be deleted and recreated.This gives output like
JVMSHRC010I Shared cache “client6” is destroyed
JVMSHRC158I Created shared class cache “client6”
JVMSHRC166I Attached to cache “client6”, size=20971328 bytes
This was especially useful when tuning the storage allocations.
Delete the cache independently
java -Xshareclasses:cacheDir=/tmp,name=client6,destroy
How to allocate the size of the cache
You specify the storage allocations using -Xsc.. (where sc stands for shareclasses)
- -Xscmx100m the size of the shared cache
- -Xscmaxaot20m the maximum number of bytes in the class cache to reserve for Ahead of Time (AOT) data.
- –Xscmaxjitdata1m the maximum number of bytes in the class cache that can be used for JIT data.
If you have -Xsharedcache:verbose… specified then when the JVM shuts down you get
JVMSHRC168I Total shared class bytes read=11660. Total bytes stored=5815522
JVMSHRC818I Total unstored bytes due to the setting of shared cache soft max is 0.
Unstored AOT bytes due to the setting of -Xscmaxaot is 1139078.
Unstored JIT bytes due to the setting of -Xscmaxjitdata is 131832.
This shows the values of maxaot and maxjitdata are too small they were
-Xscmx20m
-Xscmaxaot2k
-Xscmaxjitdata2k
When the values were big enough I got
JVMSHRC168I Total shared class bytes read=12960204. Total bytes stored=8885038
JVMSHRC818I Total unstored bytes due to the setting of shared cache soft max is 0.
Unstored AOT bytes due to the setting of -Xscmaxaot is 0.
Unstored JIT bytes due to the setting of -Xscmaxjitdata is 0.
How big a cache do I need?
If you use -Xshareclasses:verbose… it will display messages
for example
JVMSHRC166I Attached to cache “client6”, size=2096960 bytes
JVMSHRC269I The system does not support memory page protection
…
JVMSHRC096I Shared cache “client6” is full. Use -Xscmx to set cache size.
JVMSHRC168I Total shared class bytes read=77208. Total bytes stored=2038042
Message JVMSHRC096I Shared cache “client6” is full. Use -Xscmx to set cache size, tells you the cache is full – but no information about how big it needs to be.
You can use
java -Xshareclasses:cacheDir=/tmp,name=client6,printStats
to display statistics like
-Xshareclasses persistent cache disabled]
[-Xshareclasses verbose output enabled]
JVMSHRC159I Opened shared class cache "client6"
JVMSHRC166I Attached to cache "client6", size=2096960 bytes
JVMSHRC269I The system does not support memory page protection
JVMSHRC096I Shared cache "client6" is full. Use -Xscmx to set cache size.
Current statistics for cache "client6":
cache size = 2096592
softmx bytes = 2096592
free bytes = 0
ROMClass bytes = 766804
AOT bytes = 6992
Reserved space for AOT bytes = -1
Maximum space for AOT bytes = 1048576
JIT data bytes = 212
Reserved space for JIT data bytes = -1
Maximum space for JIT data bytes = 1048576
Zip cache bytes = 1131864
Startup hint bytes = 0
Data bytes = 13904
Metadata bytes = 12976
Metadata % used = 0%
Class debug area size = 163840
Class debug area used bytes = 119194
Class debug area % used = 72%
Cache is 100% full
This show the cache is 100% full, and how much space is used for AOT and JIT. The default value of -Xscmx I had was almost 16MB. I made it 200MB and this was large enough.
I could not find a way of getting my program to issue printStats.
How do I harden the cache?
You can use use the
java -Xshareclasses:cacheDir=/tmp,name=zosmf,verbose,snapshotCache
command to create the cache on disk. Afterwards the listAllCaches command gave
Cache name level cache-type feature client6 Java8 64-bit non-persistent cr client6 Java8 64-bit snapshot cr
Showing the non persistent data space, and the snapshot file.
You can use the restoreFromSnapshot to restore from the file to the data cache; before you start your Java program. You would typically do this after an IPL.
How can I tell what is going on and if shared classes is being used?
The java options “-verbose:dynload,class
reports on the
- dynamic loading of the files, and processing them,
- what classes are being processed.
For example
<Loaded java/lang/reflect/AnnotatedElement from /Z24A/usr/lpp/java/J8.0_64/lib/rt.jar>
< Class size 3416; ROM size 2672; debug size 0>
< Read time 1196 usec; Load time 330 usec; Translate time 1541 usec>
class load: java/lang/reflect/AnnotatedElement from: /Z24A/usr/lpp/java/J8.0_64/lib/rt.jar
class load: java/lang/reflect/GenericDeclaration from: /Z24A/usr/lpp/java/J8.0_64/lib/rt.jar
dynload gave
<Loaded java/lang/reflect/AnnotatedElement from /Z24A/usr/lpp/java/J8.0_64/lib/rt.jar>< Class size 3416; ROM size 2672; debug size 0>
< Read time 1196 usec; Load time 330 usec; Translate time 1541 usec>
this tells you a jar file was read from the file system, and how long it took to process it.
class gave
class load: java/lang/reflect/AnnotatedElement from: /Z24A/usr/lpp/java/J8.0_64/lib/rt.jar
class load: java/lang/reflect/GenericDeclaration from: /Z24A/usr/lpp/java/J8.0_64/lib/rt.jar
This shows two classe were extracted from the jar file.
In a perfect system you will get the class load entries, but not <Loaded….
Even when I had a very large cache size, I still got dynload entries. These tended to be loading class files rather than jar files.
For example there was a dynload entry for com/ibm/tcp/ipsec/CaApplicationProperties. This was file /usr/lpp/zosmf./installableApps/izuCA.ear/izuCA.war/WEB-INF/classes/com/ibm/tcp/ipsec/CaApplicationProperties.class
If you can make these into a .jar file you may get better performance. (But you may not get better performance, as it may take more time to load a large jar file).
I also noticed that there was dynload for com/ibm/xml/crypto/IBMXMLCryptoProvider which is in /Z24A/usr/lpp/java/J8.0_64/lib/ext/ibmxmlcrypto.jar, so shared classes has some deeper mysteries!
What happens if the .jar file changes?
As part of the class load, it checks the signature of the file on disk, matches the signature on the data space. If they are different the data space will be updated.