Minor GC, major GC, full GC: you see these words everywhere, but not always with the meaning the official documentation gives them.

Most objects die young. So the JVM keeps new objects in the young generation and long-lived ones in the old generation. A GC that only cleans the young generation is fast, and it runs often.

Why generations?

Oracle’s official guide to the garbage collector starts from a simple fact: most objects live for a very short time. This is called the generational hypothesis. An object created for a request, a loop or a calculation is useless almost right away.

If the JVM keeps new objects apart from long-lived ones, it can often clean the small area of new objects, where almost everything is dead, without scanning the whole heap every time.

How an object moves: eden, survivor, old

How an object moves in the heap: it is created in eden, moves from one survivor space to the other at each minor collection, then it is promoted to the old generationHeapYoungnew objectsEdenobjects are created hereobjectSurvivor 0the two survivor spacesSurvivor 1take turns; one is emptyOldlong-lived objectsobject1231Minor collection: the live object is copied from eden to a survivor space.2At each minor collection, it moves to the other survivor space; its age goes up.3After enough copies (MaxTenuringThreshold, 15 by default): promoted to old.

The young generation has three parts: eden and two survivor spaces.

  1. An object is almost always created in eden.
  2. When the young generation is full, the GC cleans it. Objects that are still alive are copied to a survivor space, and eden is empty again.
  3. At the next GC, live objects move from one survivor space to the other. One of the two is always empty.
  4. After a number of copies, or when the survivor spaces are full, the object is copied to the old generation. We say it is promoted.

You set the maximum number of copies with -XX:MaxTenuringThreshold. The default is 15.

Minor, major, full: what the docs really say

In Oracle’s guide:

  • a minor collection only cleans the young generation;
  • a major collection cleans the whole heap, when the old generation is full. It usually takes much longer;
  • the term full GC shows up, for example, for a complete clean-up asked for by System.gc().

Many articles say something else: “major GC = old generation only, full GC = the whole heap”. That is not how the official guide defines it.

And in the logs, the words depend on the GC. G1, the default GC, never writes “minor” or “major”:

[0.238s] GC(0) Pause Young (Normal) (G1 Evacuation Pause) 35M->3M(64M) 2.406ms
[0.287s] GC(34) Pause Young (Mixed) (G1 Evacuation Pause) 60M->35M(64M) 0.215ms
[0.335s] GC(82) Pause Full (System.gc()) 53M->27M(64M) 3.010ms

A Young (Normal) pause cleans the young generation. A Young (Mixed) pause cleans the young generation plus part of the old one. ZGC, on the other hand, does write Minor Collection and Major Collection:

[0.246s] GC(3) Minor Collection (Allocation Rate) 52M(81%)->52M(81%) 0.008s
[0.503s] GC(152) Major Collection (System.gc()) 38M(59%)->30M(47%) 0.009s

So when you read a GC log, first check which GC wrote it.

When does G1 run a full GC?

With G1, a full GC is a last resort: it compacts the whole heap, and the docs warn that it can be very slow. It mostly happens in two cases:

  • the heap is too full: the application creates objects faster than G1 can free space in the old generation;
  • someone asks for it: a call to System.gc(), from the application or from a tool.

A full GC now and then is not a problem. Full GCs that keep coming back are a warning sign: the heap is too small, or there is a memory leak.

What has changed

The G1 heap: regions of the same size; eden, survivor and old regions are mixed, between free regionsG1 heapregions of the same size (4 MB here), mixed in memoryEOSOEOOEOOEEOOSOEOOEOEOOEOOOEOSOEEdenSSurvivorOOldfreeYoung generation = eden and survivor regions; old generation = old regions.A mixed pause cleans the young generation plus some of the old regions.

Since Java 9, G1 is the default GC. It no longer splits the heap into two big blocks: it divides it into regions of the same size (4 MB on a machine with 32 GB of memory). The young and old generations are sets of regions, and these regions are not always next to each other in memory.

What you still read onlineWhat is true todaySince
The heap is split into two fixed blocks, young and oldWith G1, the heap is made of regions of the same size; the young and old generations are sets of regionsJava 9 (G1 by default)
ZGC has no generationsZGC is generational: an option in Java 21, the default in Java 23, the only mode since Java 24 (-XX:+ZGenerational is ignored, with a warning)Java 21 to 24
Major GC = cleaning the old generationIn Oracle’s guide, a major collection cleans the whole heap—
You tune the young generation with -Xmn or -XX:NewRatioWith G1, the docs advise against it: it mostly turns off pause-time control—

Sources: Oracle’s garbage collection guide (JDK 25), JEP 248 (G1 by default), JEP 439, JEP 474 and JEP 490 (generational ZGC).

The options in short

  • -Xmn: the size of the young generation (initial and maximum);
  • -XX:NewRatio: the size of the old generation compared to the young one (2 by default: the old generation is twice as big);
  • -XX:SurvivorRatio: the size of eden compared to one survivor space (8 by default);
  • -XX:MaxTenuringThreshold: the number of copies before promotion (15 by default).

With G1, it is better not to fix the size of the young generation: G1 adjusts it by itself to meet its pause-time goal.

Summary

Objects are born in eden, survive a few GCs in the survivor spaces, and the long-lived ones end up in the old generation. “Minor” means the young generation; “major”, in Oracle’s docs, means the whole heap. With G1, you rather see young, mixed and full pauses, and the heap is made of regions.

Further reading