Generations in JVM

Generational garbage collection is one of strategies used to automatically remove useless objects from memory. JVM has 2 categories of generations: young and old.

In this article we'll discover these 2 generations - in 2 first parts. We'll also approach one of concepts related to them, stop-the-world event.

What is young generation ?

Every initialized object goes to JVM heap, and more exactly, to eden space located in young generation. Now, the first garbage collection on this generation occurs. Some of objects aren't reachable anymore, so they are directly removed and remaining free space between them is compacted. The rest of objects, still referenced, moves to a subpart called survivor space. This kind of collection is called minor and it causes a stop-the-world event. However, it influences latency less than the same event triggered from old generation. Minor collection is triggered when, for example, eden space is full and new object can't be created (allocation failure).

The 'age' of objects surviving to collection is increased every time when GC runs. If this age reaches a specific value, related object can be promoted to old generation. Meanwhile, the object continues to be a part of young generation. However, it lives not anymore in eden space but in one of 2 survivor spaces: from or to. One of them is always empty. It means that survived objects from survivor and eden space moves together between from and to spaces. Only when one of moving objects is considered as 'old enough', it's promoted to old generation.

But why one survivor space is always empty ? The principle hidden behind this comes from Copying Garbage Collection. It helps to avoid fragmentation work because it copies all still reachable objects to an empty memory space. If it was a simple removal, GC should in additionally compact memory space, so eliminate holes caused by removed objects. By doing a copy, removal holes are automatically compacted.

What is old generation ?

Old generation is also known as tenured generation, so don't be surprise if you meet this term elsewhere. As young generation keeps young objects, old generation is supposed to keep only old ones. And it's true. But which is the criterion of age classification in Java memory ? This criterion is called tenuring threshold and means the number of times when given objects survived garbage collection. So if one object, placed initially in young generation, survived to 4 last garbage actions, its age is 4. Suppose also that we configured the minimum age of old generations objects to 5. If 4 "survivals" old object survives to another one collection, it's promoted to old generation.

After this short story we can tell that old generation stores objects which are supposed to live very long time (because they survive consecutive young generation collections). The size of old generation is usually bigger than for young generation. Logically, it involves longer collection process. This collection process is called major collection and makes an event called "stop-the-world event". Unlike the same event in minor collection, this one usually takes more time but is executed rarely (old generation size is bigger).

Stop-the-world event

Garbage collections can have small and big impact on the JVM. As you already know, collections with small impact are called minor while with the big one, major. Major collections cause an important stop-the-world (STW). Wut why it's called so ? This names from the fact that everything is interrupted. When this event occurs, all running threads are stopped. Only GC thread is running. When collection process ends, stopped threads restart.

Execution time of major collection will depend on the old generation size. The collection consists on deleting all unreachable objects and compacting space by moving still living objects at the begin of the generation. This collection doesn't occur frequently because old objects are supposed to be long-lived.

Playing with generations

After this introduction, the time is to play with old generation. In this little game, we'll try to observe the behaviour of GC when some of old generation flags are defined. First, we'll try to put all created objects to old generation every time with -XX:+AlwaysTenure parameter. Next, we'll compare execution time with the same code doesn't contain AlwaysTenure flag. That is the code used for tests:

public class OldGenerationRun {
  public static void main(String[] args) {
    long expectedEnd = System.currentTimeMillis() + 5000;
    Map<Integer, List<Integer>> container = new HashMap<>();
    for (int j = 0; j < 200_000; j++) {
      container.put(j, new ArrayList<>());
    int i = 0;
    while (System.currentTimeMillis() < expectedEnd) {
      if (i == 20_000) {
        i = 0;
      container.put(i, new ArrayList<>());
      for (int j = 0; j < 20_000; j++) {

To resume the experiment, we can freely tell that JVM heap is always adapted to existent situation. For example, in the case of -XX:+AlwaysTenure flag we saw that unused survivor spaces decreased 10 times. In the other side, old generation grew 5 times because it accepted more and more objects. We can also observe that full ergonomic GC takes longer than allocation failure GC. And the time needed to execute ergonomic GC is always bigger. In the case of -XX:NewRatio=5 flag GC took approximately 6 seconds to execute ergonomic GC. Also the number of GC was the biggest in this case (16 against 12, 11 and 10).

This article introduces the idea of generations inside Java memory. The first part describes short-lived objects, placed inside young generation. The second part treats about old generation and objects supposed to live much more longer. The third part explains the meaning of stop-the-world event while the last one shows some tuning options and their influence on sizes of described generations.

If you liked it, you should read:

📚 Newsletter Get new posts, recommended reading and other exclusive information every week. SPAM free - no 3rd party ads, only the information about waitingforcode!