IBM i - DUMP JVM
Another tool that can be used to learn about garbage collector performance is the Dump JVM (DMPJVM) command, which provides a spool file with information about your JVM, including some of the key GC data -- initial heap size, maximum heap size, current heap size and number of collections since the JVM was started.
It also includes a dump of the objects currently in the heap, which can be helpful for analyzing object leak problems. (Object leaks occur when your application creates new objects and keeps a reference to the objects even when they're no longer needed, preventing the collector from collecting them.
Sample of the GC section of DMPJVM output:
Garbage collector parameters
Initial size: 262144 K
Max size: 240000000 K
Current values
Heap size: 449952 K
Garbage collections: 278
Additional values
JIT heap size: 85728 K
JVM heap size: 186588 K
Last GC cycle time: 1302 ms
While the DMPJVM data is only a snapshot and doesn't provide the details available with verbose GC, it can be run without restarting your JVM, so it's useful for getting some information about the JVM after a problem has occurred.
Details on DMPJVM can be found in the IBM i Information Center at: http://publib.boulder.ibm.com/iseries/v5r2/ic2924/info/cl/dmpjvm.htm).
Use WRKACTJOB command to locate the JSM JVM job.
JSM
JSMJOB QOTHPRDOWN BCH .0 PGM-RUNJSM TIMW
QJVACMDSRV QOTHPRDOWN BCI .0 TIMW
Job: QJVACMDSRV User: QOTHPRDOWN Number: 422841
Use DMPJVM command to create a spool file with the JVM dump information.
DMPJVM JOB (422841/QOTHPRDOWN/QJVACMDSRV)
Sample DMPJVM on the JSM JVM:
Java Virtual Machine Information 422841/QOTHPRDOWN/QJVACMDSRV
........................................................................
Classpath
........................................................................
java.version=1.2
/QIBM/ProdData/Java400/jdk12/lib/jdkptf12.zip:/QIBM/ProdData/Java400/jdk12/lib/rt.jar:/QIBM/ProdData/Java400/jdk12/lib/i18n.jar:/QIBM/ProdData/Java400/ext/IBMmisc.jar:/QIBM/ProdData/Java400/ext/jssl.jar:/QIBM/ProdData/Java400/ext/ibmjssl.jar:/QIBM/ProdData/Java400/:./classes:./jar/activation.jar:./jar/jsm.jar:./jar/jsmnative.jar:./jar/mailapi.jar:./jar/pop3.jar:./jar/smtp.jar:./jar/xalan.jar:./jar/xerces.jar:./jar/xlrd.jar:./jar/jsmservice.jar:./jar/jsmutil.jar:./jar/mail.jar:
........................................................................
Garbage Collection
........................................................................
Garbage collector parameters
Initial size: 2048 K
Max size: *NOMAX
Current values
Heap size: 44032 K
Garbage collections: 51
........................................................................
Thread information
........................................................................
Information for 4 thread(s) of 4 thread(s) processed
Thread: 00000001 Thread-0
TDE: B000100007CCA000
Thread priority: 5
Thread status: Running
Thread group: main
Runnable: java/lang/Thread
Stack:
java/net/PlainSocketImpl.accept(Ljava/net/SocketImpl;)V+1 (PlainSocketImpl
java/net/ServerSocket.implAccept(Ljava/net/Socket;)V+36 (ServerSocket.java
java/net/ServerSocket.accept()Ljava/net/Socket;+8 (ServerSocket.java:224)
com/lansa/jsm/d.if()Lcom/lansa/jsm/a;+0 (:0)
com/lansa/jsm/JSMManager.do(Ljava/lang/String;)V+0 (:275)
com/lansa/jsm/JSMManager.main([Ljava/lang/String;)V+0 (:311)
Locks:
None
Thread: 00000002 Reference Handler
TDE: B0001000070D4000
Thread priority: 10
Thread status: Waiting
Wait object: java/lang/ref/Reference$Lock
Thread group: system
Runnable: java/lang/ref/Reference$ReferenceHandler
Stack:
java/lang/ref/Reference$ReferenceHandler.run()V+48 (Reference.java:129)
Locks:
None
Thread: 00000003 Finalizer
TDE: B000100007CCE000
Thread priority: 8
Thread status: Waiting
Wait object: java/lang/ref/ReferenceQueue$Lock
Thread group: system
Runnable: java/lang/ref/Finalizer$FinalizerThread
Stack:
java/lang/ref/ReferenceQueue.remove(J)Ljava/lang/ref/Reference;+48 (Refere
java/lang/ref/Finalizer$FinalizerThread.run()V+3 (Finalizer.java:190)
Locks:
None
Once you've picked a reasonable starting point, start your application and let it run for a while under the maximum load that you intend to handle, giving it time to reach a steady state (a few minutes is usually sufficient). It's best to use a load-generation tool to put a constant load on your system. This allows you to tune your application in a development environment rather than a production environment.
In addition to providing a constant load (allowing you to see the effects of changes more accurately), this allows you to make changes as necessary without affecting users.
While your application is running, use the aforementioned tools to measure the impact of your changes. Your load-generation tool should also detail the throughput and response time so you can see the impact on your application's performance.
Whenever you change performance parameters such as the GC threshold, you should measure the effects on throughput and/or response time to ensure that the changes actually help. If the tools indicate that there's still room for improvement, change the threshold and try a new run. Once you've increased it too far, the throughput begins to degrade again, indicating that you must reduce the threshold.
These recommendations are based on the assumption that your system has enough main storage to handle larger heap sizes. In reality, this may not always be the case.
In systems with limited memory, it may be necessary to set the GC threshold to a lower value, which increases collection frequency and decreases heap size. This allows the entire heap to be kept in memory.
Use Work with System Status (WRKSYSSTS) command to monitor the non-database paging/faulting rates.
If these rates get too high, the heap may be too large. The definition of "too large" depends on a variety of factors--system size, number of disks and system workload--but sustained non-database paging rates greater than 10 faults per second by Java programs is generally cause for concern.
Higher paging rates are acceptable during "warm-up" periods.
High paging rates may result from having the GC threshold set too high or may be a symptom of a larger problem.
In this case, the first step should be to isolate the JVM in its own memory pool.
This reduces the effects that other applications may have on the JVM and makes it easier to identify whether the problem is with the GC settings, system configuration or simply not enough hardware to handle the workload.
In cases where memory is especially limited, it may be useful to set the maximum heap size.
Normally, this should be left at the default value *NOMAX, which means that GC runs only when the GC threshold has been reached.
If a maximum heap size is set, the collector runs whenever the heap reaches that maximum size.
However, unlike a normal GC, if the maximum size is reached, all application threads must wait until the collector has finished before they can continue running. This results in undesirable pause times.
Therefore, it's preferred to use the maximum heap size as a safety net to handle times of unexpected heap growth and ensure that the heap doesn't grow larger than the available memory.
The GC threshold should be set so that this maximum size is never actually reached under normal circumstances.
Tuning the collector is one way to reduce the amount of time spent in GC. Another way is to reduce the number of objects being created. (Note: Tips for reducing object creation are common to all platforms and documented in several places.