Generational garbage collection
Most real-world applications tend to perform a lot allocation of 
short-lived objects (in other words, objects that are allocated, used 
for a brief period, and then no longer referenced). A generational 
garbage collector attempts to exploit this observation in order to be 
more CPU efficient (in other words, have 
higher throughput). (More formally, the hypothesis that most applications have this behavior is known as the 
weak generational hypothesis.)
It is called “generational” because objects are divided up into 
generations.
 The details will vary between collectors, but a reasonable 
approximation at this point is to say that objects are divided into two 
generations:
- The young generation is where objects are initially allocated. In other words, all objects start off being in the young generation.
 
- The old generation is where objects “graduate” to when they have spent some time in the young generation.
 
The reason why generational collectors are typically more efficient, is that they 
collect the young generation separately
 from the old generation. Typical behavior of an application in steady 
state doing allocation, is frequent short pauses as the young generation
 is being collected – punctuated by infrequent but longer pauses as the 
old generation fills up and triggers a full collection of the entire 
heap (old and new). If you look at a heap usage graph of a typical 
application, it will look similar to this:
  | 
| Typical sawtooth behavior of heap usage with the throughput collector | 
 
The ongoing sawtooth look is a result of young generation garbage 
collections. The large dip towards the end is when the old generation 
became full and the JVM did a complete collection of the entire heap. 
The amount of heap usage at the end of that dip is a reasonable 
approximation of the actual 
live set at that point in time. 
(Note: This is a graph from running a stress test against a Cassandra 
instance configured to use the default JVM throughput collector; it does
 not reflect out-of-the-box behavior of Cassandra.)
Note that simply picking the “current heap usage” at an arbitrary point in time on that graph 
will not give you an idea of the memory usage of the application. I cannot stress that point enough. What is typically considered the memory “usage” is the 
live set,
 not the heap usage at any particular time. The heap usage is much more a
 function of the implementation details of the garbage collector; the 
only effect on heap usage from the memory usage of the application is 
that it provides a 
lower bound on the heap usage.
Now, back to why generational collectors are typically more efficient.
Suppose our hypothetical application is such that 90% of all objects 
die young;
 in other words, they never survive long enough to be promoted to the 
old generation. Further, suppose that our collection of the young 
generation is compacting (see previous sections) in nature. The cost of 
collecting the young generation is now roughly that of tracing and 
copying 10% of the objects it contains. The cost associated with the 
remaining 90% was quite small. Collection of the young generation 
happens when it becomes full, and is a stop-the-world pause.
The 10% of objects that survived may be promoted to the old generation 
immediately, or they may survive for another round or two in young 
generation (depending on various factors). The important overall 
behavior to understand however, is that objects start off in the young 
generation, and are 
promoted to the old generation as a result of 
surviving in the young generation.
(Astute readers may have noticed that collecting the young generation 
completely separately is not possible – what if an object in the old 
generation has a reference to an object in the new generation? This is 
indeed something a garbage collector must deal with; a future post will 
talk about this.)
The optimization is quite dependent on the 
size of the young 
generation. If the size is too large, it may be so large that the pause 
times associated with collecting it is a noticeable problem. If the size
 is too small, it may be that even objects that die young do not die 
quite quickly 
enough to still be in the young generation when they die.
Recall that the young generation is collected when it becomes full; this
 means that the smaller it is, the more often it will be collected. 
Further recall that when objects survive the young generation, they get 
promoted to the old generation. If most objects, despite dying young, 
never have a chance to die in the young generation because it is too 
small – they will get promoted to the old generation and the 
optimization that the generational garbage collector is trying to make 
will fail, and you will take the full cost of collecting the object 
later on in the old generation (plus the up-front cost of having copied 
it from the young generation).