gen has been collected. Also, this example is from Java 7; the Java 8 output will include sim-
ilar information on the metaspace.) Because there is substantially more work to do in a full
GC, it has taken 1.3 seconds of real time, and 4.4 seconds of CPU time (again for four paral-
1. The throughput collector has two operations: minor collections and full GCs.
2. Timings taken from the GC log are a quick way to determine the overall impact of
GC on an application using the throughput collector.
Adaptive and Static Heap Size Tuning
Tuning the throughput collector is all about pause times and striking a balance between the
overall heap size and the sizes of the old and young generations.
There are two trade-offs to consider here. First, there is the classic programming trade-off of
time versus space. A larger heap consumes more memory on the machine, and the benefit of
consuming that memory is (at least to a certain extent) that the application will have a higher
The second trade-off concerns the length of time it takes to perform GC. The number of full
GC pauses can be reduced by increasing the heap size, but that may have the perverse effect
of increasing average response times because of the longer GC times. Similarly, full GC
pauses can be shortened by allocating more of the heap to the young generation than to the
old generation, but that in turn increases the frequency of the old GC collections.
The effect of these trade-offs is shown in Figure 6-3 . This graph shows the maximum
throughput of the stock servlet application running in a GlassFish instance with different
heap sizes. With a small 256 MB heap, the application server is spending quite a lot of time
in GC (36% of total time, in fact); the throughput is restricted as a result. As the heap size is
increased, the throughput rapidly increases—until the heap size is set to 1,500 MB. After
that, throughput increases less rapidly: the application isn't really GC-bound at that point
(about 6% of time in GC). The law of diminishing returns has crept in here: the application
can use additional memory to gain throughput, but the gains become more limited.