Oracle generational collectors

The Oracle JVM organized its heap into generations to improve the efficiency of its garbage collection, and to reduce the frequency and duration of user-perceivable garbage collection pauses.

The premise behind generational collection is that memory is managed in generations or in pools of memory with different ages (see Figure 1).

Figure 1. Heap layout
The figure displays a heap layout, where objects are stored.

New objects are allocated in the eden. When the eden fills up, the JVM issues a scavenge GC or minor collection to move the surviving objects into one of the two survivor or semi spaces. The JVM does this by first identifying and moving all referenced objects in the eden to one of the survivor space. At the end of the scavenge GC, the eden is empty (since all the referenced objects are now in the survivor space) and ready for object allocation.

The scavenge GC's efficiency depends on the amount of referenced objects it has to move to the survivor space and not on the size of the eden. The higher the amount of referenced objects, the slower the scavenge GC. Studies, however, have shown that most Java™ objects live a very short time. Since most objects live for a short time, one can typically create large edens.

Referenced objects in the survivor space bounce between the two survivor spaces at each scavenge GC until it either becomes unreferenced or the number of bounces has reached the tenuring threshold. If the tenuring threshold is reached, that object is migrated up to the old heap.

When the old heap fills up, the JVM issues a Full GC or major collection. In a Full GC, the JVM has to first identify all the referenced objects. When that is done, the JVM sweeps the entire heap to reclaim all free memory (for example, because the object is now dead). Finally, the JVM then moves referenced objects in order to defragment the old heap. The efficiency of the Full GC is dependent on the amount of referenced objects and the size of the heap. For more information see The Java HotSpot Performance Engine Architecture, and extensive Java SE Hotspot information.

Heap settings

It is both a curse and a blessing that the Oracle-based JVMs provide many parameters to control the JVM heap configuration. Tuning the Oracle generational collectors can be part art and part guess work. You may opt for the Keep It Simple Strategy Principle. In the following example, only specify the starting (-Xms) and maximum (-Xmx) heap size:


   java -server -Xms358m -Xmx358m weblogic.Server
   

When choosing the JVM settings, you should keep the following in mind:

  • Set the initial and max heap size the same - This eliminates the need of the JVM to decide when to expand or shrink the heap. This could also prevent a class of OutOfMemory exceptions where there is not enough swap space when the JVM needs to expand the overall heap.
  • By default, the Sterling Selling and Fulfillment Foundation caches reference data for performance. Depending on your data setup, you may have to increase the heap size or reduce the numbers of cached records. See Performance feature - reference data caching for more information on the caching feature.
  • Ensure that the node has enough physical memory so that portions of the heap are not paged out.
    Note: Please make sure you test your JVM heap settings with representative workloads and data under anticipated peak processing rates. In addition, you should run these tests for a number of days. Depending on your processing mix, the JVM heap settings could be different for the JVMs running the agents, the application servers and the JMS servers.

When setting the young heap, keep the following recommendations in mind:

  • Set the initial and max eden size the same - This eliminates the need of the JVM to decide when to expand or shrink the eden.
  • The cost of a scavenge GC is dependent on the amount of active objects that has to be moved to the survivor space and not on the size of the eden. Therefore, one can usually allocate a large eden.
  • Allocate the eden large enough so that the scavenge GCs are not occurring too frequently (e.g., less than once per minute) and the collection service time is reasonably short (e.g., less than 0.3 seconds).
  • Alternatively, create more JVMs to spread out the load. This reduces the amount of active objects in a JVM which, in turn, reduces the frequency and the duration of the scavenge GC.

Keep in mind the following when configuring the survivor spaces:

  • The survivor spaces must be large enough to store all the active objects coming from the eden as well as the sum of active objects that have an age that is less than the tenuring threshold.

Keep in mind the following when configuring the old heap:

  • The amount of free space in the old heap must be larger than both the eden size plus one of the survivor space. If the free space is less, the JVM resorts to using Full GCs (see Young generation guarantee below).
  • The cost of a Full GC is dependent on the amount of active objects as well as the size of the old heap. A Full GC is typically a lot more noticeable to the end user than a scavenge GC. A Full GC on a 256MB old heap can take up to three seconds.
  • Keep in mind that Sterling Selling and Fulfillment Foundation provides the ability to cache records. If you activate this feature, you should monitor the occurrence of full GC to see if the old generation is large enough. See Performance feature - reference data caching for more information on the caching feature.

Therefore, you should allocate the old heap large enough so that Full GCs are not occurring too frequently (e.g., more than once in 15 minutes) and the collection service time is less than 2 seconds

Young generation guarantee

Note: Young Generation Guarantee is valid only for serial collector from JDK 1.5 (and later).
Starting in JDK 1.3.1_05, the Oracle JDKs implemented a conservative garbage collection policy called the Young Generation Guarantee. Before starting a GC, the JVM checks if the free space in the old heap (OLD FREE) is larger than the sum of the eden. The premise is that it is possible (though highly unlikely) that every object in the eden remains alive and uncollected and has to be promoted to the old heap. If that ever happens, the Young Generation Guarantee ensures that there is enough free space in the old heap for all the promoted objects.

Starting recommendations

We recommend that you try the default generational settings with a 384M and a 768M heap for your agents and application servers respectively:


   java -server -Xms768m -Xmx768m \
        -XX:MaxPermSize=256m \
        weblogic.Server
   

Another approach is to set the overall heap to 1024MB with a 200MB young generation.

You have to regularly monitor the "health" of the garbage collection and adjust accordingly. For example:

  • If you notice that the amount of heap free after a Full GC is approaching 500MB (the capacity of the old heap), you could eventually get java.lang.OutOfMemory exceptions. You should investigate why your JVM is keeping that many live objects. For example, with your data, you may have large reference data caches (see Performance feature - reference data caching).
  • Conversely, if the amount of heap free after a Full GC is much smaller than the old heap (with similar load tests), you may consider reducing the old heap.
  • Increase the overall heap size - However, make sure the Full GC takes less than 2 seconds.
  • You must ensure that the node has enough physical memory so that portions of the heap are not paged out.

The optimum JVM heap setting depends on your workload characteristics, your workload concurrency levels, your workload complexity, and so forth. The JVM heap setting can be (and often is) different between the application servers and agents. In addition, the settings may be different between some agents. As a result, you must periodically check the effectiveness of each JVM's heap setting.

Garbage collection statistics

We recommend that you continuously collect garbage collection statistics for all JVMs even in production. The collection overhead is minor compared to the benefit. With the statistics, you can tell if:

  • A JVM has or is about to run into a memory leak.
  • The garbage collection is efficient.
  • Your JVM heap settings are optimal.
    
       
    

For a Oracle JVM, the following statistics are displayed if you enable -XX:+PrintGCDetails, -XX:+PrintGCTimeStamps, and -Xloggc:file:


   0.000: [GC 0.001: [DefNew: 32192K->511K(33152K), 0.0383176 secs]
32192K->511K(101440K), 0.0385223 secs]
   1.109: [GC 1.110: [DefNew: 32703K->198K(33152K), 0.0344874 secs]
32703K->697K(101440K), 0.0346844 secs]
   

To ensure the previous file is not overwritten after a restart, parameterize the "file" in -Xloggc:file.

Note: Create the GC log file name with the name of the workload and the starting time. In the example below the -XX:+PrintGCTimeStamps directive provides relative times of the GC from the time the JVMs started for the WebLogic server. The starting time in the file name allows you to determine when the GCs occurred:

   WORKLOAD=SCHEDULE
   gclog_file=${WORKLOAD}_‘date +%Y%m%d-%H%M%S‘
   java -verbosegc -XX:+PrintGCTimeStamps -Xloggc:${gclog_file}
weblogic.Server
If you want the GC logs for Oracle JVM to include date information, use the "-XX:+PrintGCDateStamps Java argument. IBM® JDK provides the date/time information, by default.
Note: For Windows, format the example appropriately.