IBM JDK 1.5 introduced the use of generational GC. Prior to that, the whole heap was divided into Large Object Area (LOA) and Small Object Area (SOA). No consideration was given to the age of an object.
Generational GC attempts to minimize the number of objects to be inspected during GC. It takes into account the age of the objects. The mechanism is similar to the generational GC of Sun HotSpot and JRockit. There are slight differences.
Enabling Generational GC
Generational GC is not enabled by default in IBM JDK 1.5. To enable it, use the gencon GC policy. This is done by adding the following command line argument.
-Xgcpolicy:gencon
Heap Partitions
Partitioning the heap in regions is key to minimizing the number of objects to be inspected during GC. When generational GC is enabled, the heap is divided into two spaces:
- The new space.
- The tenured space.
The new space is further divided into two zones:
- Allocate space.
- Survivor space.
Initially, the survivor space is completely empty. A new object is always created in the allocate space.
If when creating a new object an allocation failure takes place in the allocate space, a minor GC called scavenge is started. Scavenge works as follows.
All live objects from the allocate space are moved to the survivor space. The allocate space becomes completely empty of any live objects. The roles of the allocate and survivor spaces are then switched.
New objects are then created in the new allocate space.
If during scavenge, it is detected that a live object to be moved from the allocate space has survived N number of previous scavenge attempts, the object is moved to the tenured space instead. Where N is called the tenure age and is dynamically determined by the JVM.
It is expected that if an object has survived multiple scavenge attempts, it is probably a long lived object. There not much point is inspecting that object during every GC. By moving that object to the tenured space we reduce the number of objects to be inspected during a scavenge.
If after a scavenge and allocation failure continues in the new allocate space, the new area is grown.
If during tenuring, the tenured space has allocation failure a GC of the tenured space will be needed.
Setting Sizes
The –Xms and –Xmx options continue to set the total initial and maximum sizes of the heap.
To set the initial and maximum sizes of the new space, use the –Xmns and –Xmnx options. For example:
-Xms5m -Xmns2m
The total initial heap size is 5MB. Out of which 2MB will be for new space. The remaining 3MB will be for the old space.
You can also set the initial and maximum size of the tenured (old) space using –Xmos and –Xmox. But, avoid setting both new and tenured space sizes. It is best to set the size of one space and let the system use the remaining heap for the other space.
To view the current sizes of various spaces, use the –verbose:sizes option. For example:
-verbosegc -Xms5m -Xgcpolicy:gencon -verbose:sizes –Xmns2m
This will output:
-Xmca32K RAM class segment increment -Xmco128K ROM class segment increment -Xmns2M initial new space size -Xmnx253764K maximum new space size -Xms5M initial memory size -Xmos3M initial old space size -Xmox1015058K maximum old space size -Xmx1015058K memory maximum -Xmr16K remembered set size -Xmso32K operating system thread stack size -Xiss2K java thread stack initial size -Xssi16K java thread stack increment -Xss256K java thread stack maximum size
Understanding Generational Verbose GC Output
When a scavenge is performed, only the new or nursery area is collected. The verbose GC output looks like this.
<af type="nursery" id="1" timestamp="Jun 22 22:46:35 2010" intervalms="0.000">
<minimum requested_bytes="16" />
<time exclusiveaccessms="0.014" meanexclusiveaccessms="0.014" threads="0" lastthreadtid="0x00172F00" />
<refs soft="3" weak="6" phantom="1" dynamicSoftReferenceThreshold="32" maxSoftReferenceThreshold="32" />
<nursery freebytes="0" totalbytes="1048576" percent="0" />
<tenured freebytes="3029168" totalbytes="3145728" percent="96" >
<soa freebytes="2871984" totalbytes="2988544" percent="96" />
<loa freebytes="157184" totalbytes="157184" percent="100" />
</tenured>
<gc type="scavenger" id="1" totalid="1" intervalms="0.000">
<flipped objectcount="8514" bytes="467600" />
<tenured objectcount="0" bytes="0" />
<finalization objectsqueued="1" />
<scavenger tiltratio="50" />
<nursery freebytes="463696" totalbytes="1048576" percent="44" tenureage="10" />
<tenured freebytes="3029168" totalbytes="3145728" percent="96" >
<soa freebytes="2871984" totalbytes="2988544" percent="96" />
<loa freebytes="157184" totalbytes="157184" percent="100" />
</tenured>
<time totalms="1.962" />
</gc>
<nursery freebytes="461648" totalbytes="1048576" percent="44" />
<tenured freebytes="3029168" totalbytes="3145728" percent="96" >
<soa freebytes="2871984" totalbytes="2988544" percent="96" />
<loa freebytes="157184" totalbytes="157184" percent="100" />
</tenured>
<refs soft="3" weak="2" phantom="1" dynamicSoftReferenceThreshold="32" maxSoftReferenceThreshold="32" /> <time totalms="2.023" />
</af>
The af type and gc type clearly shows that it is a scavenge type GC.
The <nursery> element appears in three places. The first one shows to size of the new space and the amount of free space available. The second one shows the same metrics right after scavenge. The third one shows the metrics after the new object has been allocated (the object that could not be allocated earlier that resulted in an allocation failure). The sizes of the tenured space should not change before and after a scavenge.
The -Xtgc:excessiveGC option comes handy to detect any GC related performance problem. This will output the following after every GC.
excessiveGC: gcid="6" intimems="7.014" outtimems="284.637" percent="2.40" averagepercent="0.40"
Here, intimems shows the amount of time spent doing the last GC (with GC id of 9). The outtimems parameter shows the interval between the last two GCs (GC id 8 and 9). The percent and averagepercent parameters show the percentage of the time spent doing GC compared to normal execution of the JVM.
By default, verbose GC output goes to native standard error file. The –Xverbosegclog option allows you to route verbose GC output to a different file. For example:
–Xverbosegclog:/tmp/gc.log