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.
Issuing commands to manage the shared classes 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
Whem 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>
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.