Calculating storage requirements for JVM servers

To run a JVM server successfully in a CICS® region, you must ensure that enough free MVS™ storage is available for both the JVM and its deployed applications to use.

About this task

The storage that is required for a JVM server, and the Java™ applications in it, does not come from CICS-managed storage areas such as the DSA, EDSA, or GDSA. Some storage areas are managed by the Language Environment® handling requests, such as malloc() issued by C code. The remaining storage areas are managed directly by the JVM, by using z/OS® storage management requests such as IARV64. Both of these storage area management types use storage from the available MVS private areas. It is important to ensure that sufficient non-allocated private area region storage is available in the 24-bit, 31-bit, and 64-bit addressing areas. CICS cannot use its short-on-storage mechanism when private area region storage is running low.
The major Java components that allocate MVS storage areas are as follows:
  • Java heap
  • Loading of Java classes
  • JIT compilation caches
  • Native stack
  • Java monitors
  • Java threads
  • UNIX shared libraries

The Java heap is a contiguous pre-allocated block of 64-bit storage that is used to store the runtime data area for all objects and arrays. It is managed by the JVM garbage collection process, and its size can only be modified if the JVM is restarted. The other JVM storage areas are more dynamic in size and their size can vary depending on usage. In addition, on top of the storage areas that are allocated by the JVM, you must also consider other components that use MVS private area and interact with the JVM such as JDBC type 2 drivers, IBM® MQ Java adapter, or third-party tools.

To estimate the amount of storage used by the JVM in the different MVS private storage areas, you can use the following procedure:

Procedure

  1. Calculate your 24-bit storage.

    Each JVM thread requires 4 KB of 24-bit storage. A single JVM server can start more than 50 background daemon threads; this number does not include the number of CICS-managed JVM server threads defined by the JVMSERVER THREADLIMIT attribute. If you are using a Liberty JVM server, the number of daemon threads can be 100 or greater.

    UNIX System Services temporarily requires 256 KB of contiguous 24-bit storage during the process of creating a new thread. The minimum 24-bit requirement is calculated as follows:

    256KB + (4KB * number_of_threads)
  2. Calculate your 31-bit storage.

    Multiple JVM components can allocate storage from the 31-bit MVS private area that includes loading of Java classes, CICS control blocks, Java thread stack, the JIT compiler, and the USS dynamic link library (DLL) files used by the JVM.

    1. Java class loading

      By default, CICS JVM servers with -Xmx (heap) values of 57GB or less use Java compressed references. Compressed references instruct the JVM to create smaller objects, and having smaller objects can improve performance. Using compressed references causes the Java objects, classes, threads, and monitors to be loaded into the LE HEAP31 storage area in 31-bit storage. If you have insufficient space in 31-bit storage, class loading fails, causing termination of the JVM. Setting the JVM command line option –Xnocompressedrefs disables the use of compressed references and instead loads the Java classes into 64-bit storage.

    2. JIT Compiler

      The JIT compiler is responsible for continuous optimization, by compiling Java byte code. Executable code is stored in the JIT code cache, and static data is stored in the JIT data cache. Prior to z/OS, Version 2 Release 3 and Java 8 SR5 the code cache is stored in 31-bit storage, whereas the data cache is stored in 64-bit storage. Depending on the number of Java applications, and the amount of JIT activity, the 31-bit JIT code cache can expand dynamically to a maximum size determined by the JVM setting -Xcodecachetotal. This defaults to 128 MB. If the cache becomes full, the JIT process stops but the JVM continues to operate with reduced potential performance. If you are using z/OS, Version 2 Release 3, you can free up more space in the 31-bit private area by upgrading to Java 8 SR5, which supports residency mode for 64-bit applications (RMODE64) for the JIT code cache. This stores the compiled JIT code in the 64-bit private area.

    3. UNIX shared libraries

      The shared library region is a z/OS® feature that enables address spaces to improve the performance of the loading of UNIX System Services dynamic link library (DLL) files, and to share the associated real storage. The shared library function is disabled by default in CICS JVM servers, but is supported by the IBM Java SDK. When the first JVM process that uses shared libraries is started in the region, the shared library region reserves storage in the 31-bit high private area. For more information, see Tuning the z/OS shared library region.

      Note:

      As an approximate guideline if using Java 8 SR5 and a single application, the first JVM server to start within a CICS region can allocate anywhere between 51M to 115M of 31-bit MVS private area depending on configuration and workload.

      The subsequent JVM servers have a lower footprint and can allocate anywhere between 8M and 73M, as the JVM DLL files need to only be loaded once.

      These figures do not include the UNIX shared library region, the value of which must also be added to the 31-bit storage if enabled.

  3. Calculate your 64-bit storage.

    Multiple JVM components can allocate storage from the 64-bit MVS private area that includes the Java heap, native thread stack, Java classes, JIT compiler output, and Java monitors. The amount of 64-bit storage that is required can be estimated as a minimum of 2 GB, with additional storage required for larger workloads or more complex configurations.

    To more accurately estimate 64-bit storage, you need to consider:
    • The maximum Java heap value, set by using -Xmx
    • The maximum number of all threads in the JVM. Each thread requires a minimum of 3 MB of Language Environment stack storage, including 1 MB of stack. This accounts for the minimum 1 MB native stack storage, 1 MB of reserve storage and the 1 MB Language Environment control block that is required to support each thread. See Identifying Language Environment storage needs for JVM servers
    • Storage for the Java classes, JIT caches, and Language Environment 64-bit heaps. You can add a best guess of 300 MB - 500 MB depending on workload and configuration
    Note:

    The Java shared class cache uses UNIX shared memory which does not count towards the CICS region's address space MEMLIMIT.

    The resulting figure needs to be rounded up to the next GB to account for the way that CICS GDSA expansion views guarded storage.

  4. Run the sample statistics program DFH0STAT to provide values used to estimate MVS storage.

    View the MVS user region and extended user region storage report for information about the use of 24-bit and 31-bit MVS storage.

    View the Storage above 2 GB report for information about the use of 64-bit MVS storage.

    • Note the values for  1  Current Unallocated Total, which indicate the current amount of unallocated 24-bit (user region) and 31-bit (extended user region) storage.
    • Note the value for  2  MEMLIMIT minus Current Address Space active, which indicates the current amount of 64-bit storage available to the CICS region.
    MVS User Region and Extended User Region
    _________________________________________________________
                                                        User Region               Extended User Region  
                                                       ______________________________________________________
      Last Monitor Sample Time . . . . . . . . . . . :  03/11/2022  16:22:13      03/11/2022  16:22:13   
      State. . . . . . . . . . . . . . . . . . . . . :                Normal                    Normal  
      Current Unallocated Total. . . . . . . . . . . :                5,956K                  392,956K          1 
      LWM Unallocated Total. . . . . . . . . . . . . :                5,956K                  392,956K  
      Current Unallocated Largest Contiguous Area. . :                5,956K                  392,168K 
      LWM Unallocated Largest Contiguous Area. . . . :                5,956K                  392,168K
      Last date and time SOS . . . . . . . . . . . . :       
      Current Tasks Waiting Because SOS. . . . . . . :                     0                         0   
      Peak Tasks Waiting Because SOS . . . . . . . . :                     0                         0  
      Total Waits Because SOS. . . . . . . . . . . . :                     0                         0  
      Time Tasks Waited Because SOS. . . . . . . . . :        00:00:00.00000            00:00:00.00000  
    
    Storage ABOVE 2GB   
    _________________________  
      MEMLIMIT Size. . . . . . . . . . . . :               15,360M    
      MEMLIMIT Set By. . . . . . . . . . . :                  JCL 
      
      Current Address Space active (bytes) :      1,143,996,416    
      Current Address Space active . . . . :             1,091M    
      Peak Address Space active. . . . . . :             1,091M       
         
      MEMLIMIT minus Current Address Space active. . . . . . . :          14,269M     2 
      MEMLIMIT minus allocated to Private Memory Objects . . . :          13,144M
      MEMLIMIT minus bytes usable within Private Memory Objects:          14,269M 
      Number of Private Memory Objects . . . . . . . . . . . . :               33 
        ....minus Current GDSA extents . . . . . . . . . . . . :               32 
      Bytes allocated to Private Memory Objects. . . . . . . . :           2,216M  =       2,323,644,416
        ....minus Current GDSA allocated . . . . . . . . . . . :           1,192M  =       1,249,902,592
      Bytes hidden within Private Memory Objects . . . . . . . :           1,125M  =       1,179,648,000
        ....minus Current GDSA hidden. . . . . . . . . . . . . :           1,124M  =       1,178,599,424
          ....minus CICS Internal Trace Table hidden . . . . . :             130M 
      Bytes usable within Private Memory Objects . . . . . . . :           1,091M  =       1,143,996,416
      Peak bytes usable within Private Memory Objects  . . . . :           1,806M  =       1,893,728,256
      Current GDSA Allocated . . . . . . . . . . . . . . . . . :           1,024M  =       1,073,741,824
      Peak GDSA Allocated. . . . . . . . . . . . . . . . . . . :           1,024M 
    
  5. Start the JVM server and run a representative Java workload.
    Observe how the values for each private storage area available change, and make sure that the private storage areas are not constrained.

What to do next

Set your Java memory limits based on the estimate you got. For instructions, see Setting the memory limits for Java.