Author: Hendrik Schreiber (hs@tagtraum.com)

# GCViewer

## Introduction

GCViewer is a little tool that visualizes verbose garbage collection data generated by Sun and IBM Java Virtual Machines (JVM). The analysis of this data can be useful for tuning applications in order to maximize the performance of the garbage collector and thus the application itself.

Supported verbose:gc formats are:

- Sun JDK 1.4 with the option `-Xloggc:<file>` (preferred)
- Sun JDK 1.3.1/1.4 with the option `-verbose:gc`
- IBM JDK 1.3.0/1.2.2 with the option `-verbose:gc`

## Installation

To install GCViewer simply download the latest version from http://www.tagtraum.com/. Put the archive into the directory where you want to install GCViewer and unpack it. Then change into the newly created directory `gcviewer-XXX`. On Windows systems, where JAR files are associated with the java launcher, you can simply double click on the file `gcviewer.jar` to start the application. In all other cases, you can start GCViewer like this:

`java -jar gcviewer.jar`

## Overview

Once you started GCViewer you will see a Swing window. The figure below depicts most of the available controls with a short description.

By using the View-menu you may turn particular lines on or off.

## Example

Mostly it's server applications that benefit from tuning garbage collection. Therefore we want to look at a very simple (somewhat artificial) example of a serverside application. In our setup the webserver jo! is pounded by Apache JMeter for a limited time. To keep this example as simple as possible, the same resource is requested again and again.

### Obtaining GC data

In order to obtain garbage collection data, jo! is started with Sun JDK 1.4.0 Server and the following parameters:

`c:\j2sdk1.4.0\bin\java -server -Xloggc:normal.gc ...` (off course this works under Unix/Linux, too)

The parameter `-Xloggc:normal.gc` tells the VM that it should write verbose garbage collection information to the file `normal.gc`. After our test run finished we open the file with GCViewer:

Probably the two most important lines in the graph are the red and the blue line. The red line indicates the total heap size, the blue line shows how much of the heap is actually used. As we can see the blue line follows a saw like pattern. If we increase the zoom to 1.000% it becomes obvious that this pattern is repeated in each tooth of the saw.

To understand why we see this doubled saw pattern, we have to take a look at the used garbage collector.

Sun JDK 1.4.0 Server uses a generational garbage collector with two young generations and an old generation. New objects are always allocated in the young generation part of the heap. Every time the young generation is full a minor garbage collection takes place. In the graph this is indicated by the little grey lines at the bottom. As you can see from the length of these lines (and the green line), minor garbage collections don't take very long. Objects, which survived some minor collections, are promoted to the older generation. Usually the older collection is full at some point, too, and needs to be cleaned. This leads to a major garbage collection that removes garbage from both the old and the younger generations. Full garbage collections are indicated by black vertical lines. As you can see in the graph (green line), full garbage collections take a lot longer than minor garbage collections. This is due to the fact that a larger part of the memory is cleaned and that the older generation uses a slower, but less memory consuming, garbage collection algorithm than the younger generation.

To summarize this: The saw pattern in the first figure (zoom 200%) shows full garbage collections, the saw pattern in the second figure (zoom 1.000%) shows minor garbage collections.

### Enlarging the new generation

How can this help us tuning the application? Well, after each minor collections the heap memory consumption is slightly higher than after the minor collection before. I.e. some objects have been promoted to the older generation. But every time a full collection occurs the memory consumption (blue line) is reduced to more or less the same value as after the last full collection. This means that even though some objects were promoted to the older generation, most of them didn't become very old either. Which means, that maybe they should not have been promoted to the older generation in the first place.

In this particular scenario it seems beneficial to increase the size of the younger generation to prevent the early promotion of medium-lived objects. For Sun JDK 1.4.0/1.3.1 this can be achieved with the unsupported parameter `-XX:NewRatio=<value>`. It defines the ratio between the young and the old generations. I.e. a NewRatio of 2 means, that the young generations use one third of the heap. The default values of this parameter differs depending on your VM, whether you use the Server HotSpot compiler or the Client HotSpot compiler and which platform you are operating on.

To see what effect a different NewRatio has on our application we start it like this:

`c:\j2sdk1.4.0\bin\java -server -XX:NewRatio=2 -Xloggc:newratio2.gc ...`

The figure below shows the result:

It is obvious that less full garbage collections occur (4 instead of 9) and that the minor collections remove more garbage (1 Mbyte instead of 0.5 MByte). Because less full garbage collections took place the accumulated pause time (Acc Pauses) caused by garbage collections decreased from 4.26s to 2.26s. This means that the application now spends only little more than half as much time on garbage collection than before. This sounds great, but to be honest - for this application the overall effect of this improvement isn't terribly large as it didn't cause excessive pause times in the first place. But still, the throughput (time the application actually runs and isn't busy with garbage collection) increased from 97.62% to 98.84%. Again - if your real world application has a throughput of over 95% you probably shouldn't bother with tuning garbage collection.

As a side effect of `NewRatio=2` we notice that the overall memory consumption (Footprint) slightly increased from 3.364 KByte to 3.604 KByte. This is due to the larger younger generation.

### Tweaking it even more

To see whether we can improve the throughput even more, we start another test run with `NewRatio=1`:

As you can see from the graph there are still four full collections - but they occur in the initialization and shutdown phases of the test run. Also, they don't seem to take a very long time. The sum of all pause times decreased from 2.26s to 1.74s and as a direct result the throughput increased to fantastic 99.02%. The downside of this improvement is the also increased footprint of 4.756 KByte.

## Tuning real applications

In our example we used a very simple scenario to demonstrate a single tuning. In a real application we would have to make sure that we can repeat a test run in order to compare the values. We also need to keep in mind, that verbose garbage collection has a huge impact on the performance of an application. Therefore you might want to think twice about collecting the data in a production environment. For the sake of repeatability and not hindering the everyday business you should set up a test environment that is identical to your production environment and run load tests that simulate real load situations. You should also measure the performance of your application without verbose garbage collection in order to measure the real effect of any garbage collection tuning.

## Conclusion

GCViewer helps you interpreting verbose GC data from your VM. Especially with Sun JVMs, manipulating generation sizes can have a large impact on the behaviour of your application. GCViewer helps you making the correct decisions and running the right tests. Off course this doesn't free you from the task of not producing too much garbage in the first place...

## Further Reading

- Tuning Garbage Collection: http://java.sun.com/docs/hotspot/gc/index.html
- Richard Jones, Rafael Lins: Garbage Collection: Algorithms for Automatic Dynamic Memory Management. New York: Wiley & Sons 1996.