Just how much does the amount of live data in the heap affect GC times? The answer can be more
than an order of magnitude.
Here's the output of a GC log from a test on my standard four-core Linux system using a 4 GB
heap (of which 1 GB is the fixed size for the new generation):
[Full GC [PSYoungGen: 786432K->786431K(917504K)]
[PSPermGen: 2349K->2349K(21248K)], 0.5432730 secs]
[Times: user=1.72 sys=0.01, real=0.54 secs]
[Full GC [PSYoungGen: 786432K->0K(917504K)]
[PSPermGen: 2349K->2349K(21248K)], 0.0687770 secs]
[Times: user=0.08 sys=0.00, real=0.07 secs]
[Full GC [PSYoungGen: 349567K->349567K(699072K)]
[PSPermGen: 2349K->2349K(21248K)], 0.7228880 secs]
[Times: user=2.41 sys=0.01, real=0.73 secs]
Notice that middle output: the application cleared most references to things in the old generation,
and hence the data in the old generation after the GC was only 210 KB. That operation took a
mere 70 ms. In the other cases, most of the data in the heap is still live; the full GC operations,
which removed very little data from the heap, took between 540 ms and 730 ms. And fortunately,
there are four GC threads running in this test. On a single-core system, the short GC in this ex-
ample took 80 ms, and the long GC required 2,410 ms (more than 30 times longer).
Using a concurrent collector and avoiding full GCs doesn't make the situation that much bet-
ter, since the time required by the marking phases of the concurrent collectors similarly de-
pends on the amount of still-live data. And for CMS in particular, the objects in a pool are
likely to be promoted at different times, increasing the chance of a concurrent failure due to
fragmentation. Overall, the longer objects are kept in the heap, the less efficient GC will be.
So: object reuse is bad. Now we can discuss how and when to reuse objects.
The JDK provides some common object pools: the thread pool, which is discussed in