A JVM manages run-time storage in several segregated heaps. Objects are grouped in these heaps according to their expected lifetime. Java™ Applications in CICS® explains the structure and content of these storage heaps.
JVMs are able to exploit the grouping of objects by using heap-specific garbage collection (the process of cleaning up unreferenced objects that are no longer in use), as follows:
The initial sizes for the storage heaps in a JVM are defined by options in its JVM profile. All of the heaps can expand within the storage available to them. The maximum sizes of the system heap and the application-class system heap are only restricted by the storage available in the Language Environment® enclave for the JVM. The maximum sizes of the middleware heap and the transient heap are restricted by the maximum size set for the nonsystem heap, which is specified in the JVM profile (using the Xmx option). Specifying the maximum size for the nonsystem heap means that you are specifying a maximum total size for the middleware and transient heaps. Remember that continuous and single-use JVMs do not have a transient heap, because these types of JVM are not reset after each use. For these types of JVM, the nonsystem heap consists only of the middleware heap, and therefore the Xmx option only limits the maximum size of the middleware heap.
You specify JVM heap sizes with the following options in a JVM profile:
Option in the JVM profile | Description | JVM default value for z/OS® | Value set by CICS-supplied sample JVM profiles | JVM types |
---|---|---|---|---|
Xinitacsh | Initial application class system heap size | 128 KB | Not specified | Not for worker, continuous, single-use |
Xinitsh | Initial system heap size | 128 KB | Not specified | Not for worker |
Xinitth | Initial transient heap size | 500 KB | Not specified (see note) | Not for master, continuous, single-use |
Xms | Initial middleware heap size | 500 KB | 16 MB (master 1 MB) | All types |
Xmx | Maximum total size for the transient + middleware heaps (nonsystem heap) | 64 MB | 32 MB (master 4 MB) | All types |
Note:
If Xinitth is
not specified and Xms is specified, then Xinitth is
set to half of Xms. In the CICS-supplied JVM profile DFHJVMPR,
the value of Xms is 16 MB, therefore Xinitth is set
to 8MB. |
In Java Applications in CICS, "Setting up JVM profiles and JVM properties files" tells you how to set up a JVM profile, and "Customizing and creating JVM profiles and JVM properties files" tells you how to customize the options in it. You can modify the storage-related options in a JVM profile without restarting CICS. To implement the new version of the JVM profile, use the CEMT SET JVMPOOL TERMINATE command to shut down and restart the JVMs in the JVM pool.
Tuning JVM storage options can reduce the storage required for each JVM, and also eliminate unnecessary CPU time spent expanding heaps and running garbage collection. In most cases, one requirement must be balanced against another. For example, a large setting for the nonsystem heap reduces the frequency of garbage collections, but also reduces the number of JVMs that CICS can have in its address space.
All heap storage requirements depend on:
You can use the CICS statistics to get an indication of a suitable value for the Xmx option. The field "Peak Nonsystem heap storage used" in the JVM Profile statistics shows the peak (or high water mark) amount of storage that was actually used by a JVM with the specified execution key and profile. As a first step for tuning, you could set the value of Xmx to this figure, rounded up to a 1MB boundary. To increase the accuracy of the result, you should purge any JVMs with the profile that you are tuning, around the time of a statistics reset (either before or immediately afterwards). This ensures that the statistics collected in the next statistics interval are a more accurate reflection of the storage usage for those JVMs.
For more accurate tuning for your JVMs, including suitable values for the transient heap size and the system heap size, you should use the output from garbage collection. The guidelines and tuning method given in Using the output from garbage collection to tune storage for JVMs are generally suitable for all types of JVM.
The IBM® Developer Kit and Runtime Environment, Java 2 Technology Edition, Version 1.4.2 Diagnostics Guide, SC34-6358, has a detailed explanation of the JVM's garbage collection process. This document is available to download from www.ibm.com/developerworks/java/jdk/diagnosis/
For CICS Transaction Server for z/OS, Version 3 Release 1, a full garbage collection is automatically requested by CICS for each JVM after every 101st transaction. In between these automatic garbage collections, if a JVM runs out of space in one of its storage heaps and is unable to allocate any more objects (an allocation failure), the Garbage Collector tries to expand the storage heap. If there is not enough free storage available to do this, because the middleware heap and the transient heap have already been expanded to fill the amount of storage specified by the Xmx option in the JVM profile, a full garbage collection is triggered to free some storage. It is generally better to tune the heap settings to avoid this situation so that, if possible, the automatic garbage collections are the only full garbage collections performed.
The output from each JVM's garbage collection process can show you:
From this output, you can see whether the JVM profile for the JVM contains the right settings for the initial and maximum sizes of the storage heaps, and check that you have not specified too much, or too little, storage for the needs of the programs that run in the JVM. When you have optimized your use of virtual storage for each JVM, you might be able to increase the number of JVMs in your CICS region.
In a non-production environment, you can collect and examine the output from garbage collection for a JVM. To do this:
Xmx=100M (or larger if needed; set higher than you could possibly use)
Xinitth=500K (not applicable for a continuous JVM)
Xms=1M
Xmaxf=1 (turns off heap shrinkage)
Xmaxe=1M (with Xmine setting, sets heap expansions to 500K)
Xmine=1M
Do not specify Xinitsh (will default to 128KB)
Do not specify Xinitacsh (will default to 128KB, if applicable)
These values are designed to ensure that the storage heaps will begin
at a size smaller than required, and expand up to the size that is actually
required to run the JVM's workload of Java programs. If you want to examine the
normal behaviour of the JVM with its present heap settings, leave the values
in the JVM profile as they are.Once you have obtained the output from garbage collection, you can use it to tune the storage heap settings in the JVM profile. The IBM Developer Kit and Runtime Environment, Java 2 Technology Edition, Version 1.4.2 Diagnostics Guide, SC34-6358, includes examples of the output from garbage collection and explains what they show.
To carry out basic tuning, you need to identify four common types of output in your file:
<GC(32): GC cycle started Fri Jun 20 09:20:25 2003
<GC(32): freed 0 bytes from Transient Heap 100% free (523776/523776) and...>
<GC(32): freed 5676656 bytes, 56% free (7763712/13761024), in 12 ms>
<GC(32): mark: 10 ms, sweep: 2 ms, compact: 0 ms>
<GC(32): refs: soft 0 (age <= 32), weak 0, final 0, phantom 0>
If the value for the Xmx option in the JVM profile is sufficient
or too large, most of the output in your file will be of this type, once heap
expansion is no longer taking place. You can base your storage heap settings
on the values in this output, as explained later in this topic.<AF[7]: Allocation Failure. need 16400 bytes, 770 ms since last AF>
<AF[7]: managing allocation failure, action=3 (114624/9697792)>
<GC(8): need to expand mark bits for 13761024-byte heap>
<GC(8): expanded mark bits by 63488 to 215016 bytes>
<GC(8): need to expand alloc bits for 13761024-byte heap>
<GC(8): expanded alloc bits by 63488 to 215016 bytes>
<GC(8): need to expand FR bits for 13761024-byte heap>
<GC(8): expanded FR bits by 126976 to 430036 bytes>
<GC(8): expanded heap by 4063232 to 13761024 bytes, 30% free>
<AF[7]: completed in 1 ms>
Heap expansion
can also occur as part of a garbage collection, in which case the allocation
failure lines might not be present. Heap expansions for the middleware heap
have no special indication of the heap type, but the allocation failure lines
associated with heap expansions for the transient heap are marked "TH_AF"
instead of "AF".
If the value for the Xms option in the JVM profile, which determines the initial size of the middleware heap, or for the Xinitth option, which determines the initial size of the transient heap, is smaller than the amount that is actually required to run the Java programs, the JVM will need to expand the affected heap, possibly several times. However, it is in fact beneficial to set Xms and Xinitth smaller than the amount that is actually required, because garbage collection and heap compaction can then take place during the heap expansion process, when the heap is smaller. If garbage collection or heap compaction occurs for the first time when the heap is large (for example, if it does not occur until CICS automatically requests a garbage collection after 101 transactions), the process is very expensive. So a correctly tuned JVM should show some output from heap expansion early on in its lifetime, and this output should cease when the heap has reached its required size. Heap expansion is only a sign of incorrect storage heap settings if it continues to occur throughout the lifetime of the JVM, in combination with heap shrinkage or with garbage collections that are caused by allocation failures.
<AF[7]: Allocation Failure. need 524 bytes, 1894 ms since last AF>
<AF[7]: managing allocation failure, action=3 (1962672/3471872)>
<GC(53): GC cycle started Fri Jun 6 07:13:12 2003
<GC(53): freed 114688 bytes from Transient Heap 96% free (507376/523776) and>
<GC(53): freed 247144 bytes, 62% free (2078744/3340800), in 6 ms>
<GC(53): mark: 5 ms, sweep: 1 ms, compact: 0 ms>
<GC(53): refs: soft 0 (age <= 32), weak 0, final 0, phantom 0>
<AF[7]: completed in 7 ms>
This output looks like the output from a garbage collection that has
been requested by CICS, except that it is surrounded by allocation failure
lines. Within the same allocation failure lines, you might also see messages
relating to heap shrinkage or heap expansion (as in the previous example).
This type of output occurs because there is insufficient space in one of the
storage heaps for the JVM to allocate an object (causing the allocation failure),
but the middleware heap and the transient heap have already been expanded
to fill the amount of storage specified by the Xmx option in the
JVM profile. The garbage collection is intended to make more storage available
to fulfil the JVM's allocation request. This type of garbage collection, particularly
when it occurs throughout the lifetime of the JVM, shows that the value for
the Xmx option in the JVM profile is insufficient for the requirements
of the Java programs, and it can indicate that the JVM has not been correctly
tuned. If you are tuning a JVM for the first time, and you have set the Xmx option to a value higher than the Java programs could possibly use, you should
not see this type of output.GC[14]: Expanded System Heap by 65536 bytes
GC[14]: Expanded ACS Heap by 65536 bytes
This type of output occurs because the JVM had insufficient space in
the system heap or in the application-class system heap. The initial size
of the system heap is determined by the Xinitsh option in the JVM
profile, and the initial size of the application-class system heap is determined
by the Xinitacsh option. (The space for the application-class system
heap is allocated in addition to the space for the system heap, and not as
a subset of the space for the system heap.) No garbage collection takes place
in the system heap or in the application-class system heap, so there is no
benefit in setting these values smaller than the amount that is actually required.The IBM Developer Kit and Runtime Environment, Java 2 Technology Edition, Version 1.4.2 Diagnostics Guide has fuller descriptions and examples of these and other types of output. The types of output listed above are those that are most significant for tuning JVMs that are used by CICS. Once you have identified these types of output in your output file, deal with them as described below.
If the output from your JVM's garbage collection includes the fourth type of output listed above, output from a request to expand the application-class system heap or the system heap, this shows that the values of the Xinitacsh or Xinitsh options in the JVM profile are too small. Locate all the output from requests to expand the application-class system heap or the system heap, and increase the values of Xinitacsh (for the application-class system heap) or Xinitsh (for the system heap) by this amount.
If the output from your JVM's garbage collection process includes the third type of output listed above, output from a garbage collection that has been caused by an allocation failure, this shows that the value for the Xmx option in the JVM profile is insufficient for the requirements of the Java programs. The extra activities that the Garbage Collector must perform to manage this situation occupy CPU time that could be saved by tuning the JVM correctly. You should normally choose a value for Xmx that provides all the space needed for the transient and middleware heaps, so that the only garbage collections that take place are those automatically requested by CICS. To determine a suitable value, in a non-production system, re-run the process described in Using the output from garbage collection to tune storage for JVMs, this time choosing a very large value for Xmx. This output file should not contain any output from garbage collections caused by allocation failures. Determine a more suitable value for Xmx using the output in the file from a garbage collection that has been automatically requested by CICS, as described later in this topic.
If the output from your JVM's garbage collection process includes the second type of output listed above, output from a heap expansion, you do not need to be concerned if this output only occurs early on in the JVM's lifetime. Remember that a correctly tuned JVM should show some output from heap expansion early on in its lifetime, and this output should cease when the heap has reached its required size. If the number of heap expansions seems excessive, you could consider increasing the value of the Xms option in the JVM profile, which determines the initial size of the middleware heap, or of the Xinitth option, which determines the initial size of the transient heap. (If the transient heap is being expanded, the allocation failure lines are marked "TH_AF" instead of "AF".) As a guide, once you have identified the maximum size needed for the transient heap and middleware heap, as described later in this topic, set the values of Xinitth and Xms to approximately 50% of these maximum values. However, it is not worth setting the value of Xinitth lower than the default setting of 500 KB.
If heap expansion continues to occur throughout the lifetime of the JVM, in combination with heap shrinkage or with garbage collections that are caused by allocation failures, this indicates that the value for the Xmx option in the JVM profile is insufficient for the requirements of the Java programs. As described above, you should normally choose a value for Xmx that provides all the space needed for the transient and middleware heaps, which you can identify by re-running the process described in Using the output from garbage collection to tune storage for JVMs and choosing a very large value for Xmx. This time, you should only see heap expansion early on in the lifetime of the JVM. Determine a more suitable value for Xmx by using the output from a garbage collection that has been automatically requested by CICS, as described next.
The output from your JVM's garbage collection process is certain to include the first type of output listed above, output from a garbage collection that has been automatically requested by CICS after every 101 transactions (provided, of course, that you have run at least 101 transactions in the JVM). You can base your storage heap settings on the values in this output.
Select the output from a garbage collection that took place towards the end of your transaction workload, when the JVM was in a steady state, with the output file showing only automatic garbage collections at that point. If the output file continues to show any of the other types of output after the initial heap expansion phase, repeat the transaction workload with a larger value specified for Xmx, until you obtain an output file where the only activity after the initial phase is the automatic garbage collections that are requested by CICS after every 101 transactions.
Now examine this output in detail to identify the high water marks for the transient and middleware heaps. Here's the example output again:
<GC(32): GC cycle started Fri Jun 20 09:20:25 2003
<GC(32): freed 0 bytes from Transient Heap 100% free (523776/523776) and...>
<GC(32): freed 5676656 bytes, 56% free (7763712/13761024), in 12 ms>
<GC(32): mark: 10 ms, sweep: 2 ms, compact: 0 ms>
<GC(32): refs: soft 0 (age <= 32), weak 0, final 0, phantom 0>
The second line of this output shows that the transient heap has 523776 bytes available out of a total heap size of 523776 bytes, so 100% of the heap is free. (This should normally be the case in an automatic garbage collection requested by CICS after every 101 transactions, because the transient heap is thrown away at the end of each transaction.) The transient heap has grown to 523776 bytes, that is, slightly larger than the default allocation of 500 KB. As noted earlier in this topic, the value of the Xinitth option (which determines the initial size of the transient heap) should normally be set to 50% of the maximum size of the heap, but it is not worth setting it lower than the default setting of 500 KB. The Xinitth option should therefore be left as the default allocation.
The third line of this output shows the same information for the middleware heap. It has 7763712 bytes available out of a total heap size of 13761024 bytes, so 56% of the heap is free. This shows that the high water mark for the middleware heap was just over 13 MB. The Xms option, which determines the initial size of the middleware heap, can therefore be set to 50% of this value, so about 7 MB. You could consider increasing this value if the number of heap expansions seems excessive.
To determine an appropriate setting for the Xmx option, which specifies the maximum total size for the middleware and transient heaps, you can add together the maximum requirements that you found for the transient heap and the middleware heap. Add an additional 500 KB as a buffer between the transient heap and middleware heap, and round up to a 1 MB boundary. In this example, with a transient heap of 511 KB, a middleware heap of 13.1 MB, and a buffer of 500 KB, the total space required is about 14.2 MB. A suitable setting for the Xmx option in this case would be 15 MB.
Bear in mind that the settings that you determine using this process are based on high water marks for storage usage. You might be able to run with lower heap sizes in the JVM profile, taking the cost of additional infrequent garbage collections when the heap expands beyond the normal amount. You need to experiment with your Java programs and determine optimum values from monitoring data.
When you have tuned each of your JVM profiles in this way, you should have found storage heap settings that minimize the need for garbage collection but use only the amount of virtual storage that is required. You might then find that you have saved virtual storage and your CICS region is able to support a larger number of JVMs. Bear in mind that there is also a basic storage cost for each JVM. This basic storage cost represents the amount of storage in the Language Environment enclave that is used for the structure of the JVM, and when you calculate the total size of the JVM, the basic storage cost must be added to the storage that is used for the storage heaps. Managing your JVM pool for performance lists the basic storage cost for each type of JVM, and tells you how to determine the number of JVMs that your CICS region can support. You should tune the Language Environment enclave settings to ensure that they are as close as possible to the storage actually used by your JVMs, as described in Tuning Language Environment enclave storage for JVMs.
The transaction used as the test case to produce these figures consisted of a simple stateless session bean, therefore these storage settings should be viewed as the minimum case.
In tests, the following storage settings for the middleware and transient heap provided good performance for a minimal stateless session bean, while keeping storage allocations to a minimum: