RadhaPublication
HomeInterviewLearning PathsRole TracksMockBooksPricing
Login / Sign UpLog in

© 2026 Radha Publication. All rights reserved.

Shop on AmazonDonateContactPrivacyTerms
Java questions
MediumJava#148 min readJul 11, 2026

Young Generation vs Old Generation.

practice
learning
Practice modeTest yourself instead of reading straight through

Hook: Interviewers love this question because it shows whether you understand why Java GC is usually fast: most objects are born, used briefly, and then disappear.

Question: What is the difference between the Young Generation and the Old Generation in Java?

Answer: In Java, the Young Generation is where new objects are usually allocated first. It is collected often because many objects die quickly. The Old Generation holds objects that have survived several garbage collections and are expected to live longer.

Interview-Ready Answer: In Java, I think of the heap as split into a young area for new, short-lived objects and an old area for long-lived objects. Most allocations go into the Young Generation, where Minor GC runs frequently and cheaply. If an object survives enough collections, it is promoted to the Old Generation, which is larger and collected less often, but those collections are usually more expensive. One useful detail is that in modern collectors like G1, the heap is region-based, but the young-versus-old idea still applies.

🧠 Memory Map
Memory map — visual summary of this topic

Core idea

Java uses a generational garbage collector, which means it groups objects by age. A generation is simply a heap area for objects of a similar lifetime. The basic assumption is very practical: most objects die young, so the JVM optimizes for that pattern.

How it works under the hood

  1. New objects are allocated in the Young Generation, usually in the Eden area. Eden is the main allocation space, and it is designed for very fast bump-pointer allocation, which is close to O(1).
  2. The JVM tracks live references from roots such as thread stacks, local variables, static fields, and registers. A GC root is anything the collector treats as definitely reachable.
  3. When Eden fills up, a Minor GC starts. A Minor GC is a collection of the Young Generation only, not the whole heap. This is why it is usually much faster than a full-heap collection.
  4. Live objects are copied out of Eden into a Survivor space. A Survivor space is a temporary young-gen area for objects that are still alive after a GC.
  5. Each surviving object gets older. The JVM increments its age after each young collection. If it survives enough times, or if Survivor space is too full, it is promoted to the Old Generation.
  6. Old Generation objects are collected less often. They are usually long-lived caches, session objects, buffers, or framework internals that remain reachable for a long time.
  7. When Old Gen gets pressured, the collector performs a more expensive old-space or mixed collection. Depending on the collector, this may be called Major GC, Mixed GC, or Full GC. The exact naming and behavior depend on the GC algorithm.

Young Gen vs Old Gen

AspectYoung GenOld Gen
Typical objectsShort-livedLong-lived
Collection frequencyHighLow
Common spaceEden + SurvivorsTenured heap
GC costUsually lowUsually higher
GoalFast allocationReduce long-term pressure

Why this design works

It is faster to collect a small young area often than to scan the entire heap every time. The JVM also uses mechanisms such as write barriers (small bookkeeping code added to reference writes) and card tables (compact memory maps that track which old regions may point to young objects) so the collector does not need to rescan everything. That is a big reason young collections stay cheap.

Important numbers and practical tuning facts

  • There is no single fixed default size for Young or Old Generation across all Java versions and collectors; the JVM sizes them ergonomically based on heap size and allocation behavior.
  • In many HotSpot collectors, an object may survive up to 15 young collections before promotion, but the JVM can promote earlier if Survivor space is tight. The related knob is MaxTenuringThreshold.
  • Minor GC pauses are often in the millisecond range, while old-heap collections can take tens to hundreds of milliseconds or more, depending on heap size and live data.
  • Allocation into Eden is typically O(1), while GC cost is closer to O(live objects collected), not O(total heap), which is why live-set size matters so much.

Version and collector differences

With G1 GC, the heap is split into same-sized regions, and the JVM decides at runtime which regions act as young or old. So the old beginner-style picture of two big fixed chunks is simplified, but the mental model still holds. Also, Metaspace is not the Old Generation; since Java 8, class metadata lives outside the Java heap in Metaspace.

Edge cases interviewers like

  • If many objects survive young collections, Young Gen becomes less effective and promotion increases old-gen pressure.
  • If Old Gen fills up, you may see long pauses, promotion failures, or messages such as GC overhead limit exceeded.
  • Large object handling depends on the collector. Some collectors may pretenure or special-case very large allocations, so do not claim every large object always goes through the same path.
  • Not all collectors expose the same phases, but the life-cycle idea remains: allocate young, survive, promote, collect later.

Memory model to remember: young gen is the nursery, old gen is the retirement home. New objects start in the nursery; only the survivors move to retirement.

Real-world story

Imagine a checkout service for an e-commerce site. Every request creates lots of tiny objects: request DTOs, validation results, temporary strings, and JSON parsing buffers. These are perfect Young Generation residents because they usually die before the request finishes.

Now suppose a developer accidentally stores a request-scoped object in a static map meant for debugging. That object is now strongly referenced for the life of the process, so it keeps surviving GC cycles and gets promoted into Old Gen. Over time, more and more request data gets stuck there.

What goes wrong: at first, everything looks fine. Then Minor GCs become more frequent because Eden keeps filling up. Soon old-gen occupancy climbs, pauses get longer, and the service starts logging repeated GC events such as young pauses followed by mixed or full collections. Users see slow checkouts, timeouts, and occasional 5xx errors during traffic spikes. The root cause is often visible in heap dumps as a growing retained set, not as a CPU bug.

Typical symptoms:

  • GC logs show frequent young collections and growing old occupancy.
  • Latency spikes happen every few seconds or minutes.
  • Heap dumps reveal objects that should have died with the request but were kept by a cache, listener, or static collection.
  • Memory usage keeps rising even when traffic drops.

The lesson: the Young/Old split is not just a theory. It directly affects whether a service can handle traffic smoothly or gets dragged into long GC pauses.

Java
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;

public class YoungVsOldGenerationDemo {
    // Objects kept here stay strongly reachable, so they are long-lived candidates.
    private static final List<Payload> longLivedCache = new ArrayList<>();

    static class Payload {
        private final String name;
        private final byte[] data;

        Payload(String name, int sizeKb) {
            this.name = name;
            this.data = new byte[sizeKb * 1024];
        }

        int touch() {
            // Touch the array so the object is clearly used.
            return data[0] + data[data.length - 1];
        }

        @Override
        public String toString() {
            return name + "(" + (data.length / 1024) + "KB)";
        }
    }

    public static void main(String[] args) throws InterruptedException {
        System.out.println("=== Short-lived allocations ===");
        runShortLivedBurst();

        System.out.println();
        System.out.println("=== Long-lived allocations ===");
        createLongLivedObjects();

        System.out.println();
        System.out.println("=== Weak reference edge case ===");
        WeakReference<Payload> weak = createAndDropReference();

        // System.gc() is only a hint, not a command. The JVM may ignore it or delay it.
        System.gc();
        Thread.sleep(200);
        System.out.println("Weak reference cleared after GC hint? " + (weak.get() == null));

        System.out.println();
        System.out.println("=== Cache cleanup edge case ===");
        if (longLivedCache.size() > 3) {
            System.out.println("Cache too large, removing oldest entries to reduce old-gen pressure.");
            while (longLivedCache.size() > 3) {
                longLivedCache.remove(0);
            }
        }
        System.out.println("Remaining cache entries: " + longLivedCache);
    }

    private static void runShortLivedBurst() {
        long checksum = 0;
        for (int i = 0; i < 20_000; i++) {
            // These objects are created and discarded quickly, which is exactly what Young Gen is optimized for.
            Payload p = new Payload("temp-" + i, 1);
            checksum += p.touch();
        }
        System.out.println("Burst checksum: " + checksum);
    }

    private static void createLongLivedObjects() {
        for (int i = 1; i <= 5; i++) {
            // Keeping references in a static collection makes these objects survive many collections.
            Payload p = new Payload("cached-" + i, 256);
            longLivedCache.add(p);
        }
        System.out.println("Cache entries: " + longLivedCache);
    }

    private static WeakReference<Payload> createAndDropReference() {
        Payload p = new Payload("temporary-strong-ref", 512);
        WeakReference<Payload> ref = new WeakReference<>(p);

        // Once the strong reference is removed, the object becomes eligible for collection.
        // Whether it is reclaimed immediately depends on the JVM and memory pressure.
        p = null;
        return ref;
    }
}

Follow-up & Tricky Questions:

  • What triggers promotion from Young to Old? Objects that survive enough young collections, or objects that cannot fit safely into Survivor space, may be promoted. The exact threshold depends on the collector and settings such as MaxTenuringThreshold.
  • What is Eden? Eden is the main allocation area inside the Young Generation. Most new objects are created there because allocation is extremely fast.
  • What are Survivor spaces? They are two small young-gen spaces used to hold objects that survive a Minor GC. They help the JVM age objects gradually before promotion.
  • Is Old Gen the same as Metaspace? No. Old Gen is part of the Java heap; Metaspace stores class metadata outside the heap starting with Java 8.
  • Why not just make the heap one big space? Because most objects die young. Separating young and old lets the JVM collect the most garbage with the least work.
  • How do I see this in practice? Turn on GC logging such as -Xlog:gc* on modern JDKs and watch how young pauses happen more often than old collections.
  • Tricky: Does System.gc() move objects to Old Gen? No. It is only a hint to the JVM, and object movement depends on the collector, reachability, and current heap pressure.
  • Tricky: Are all large objects always in Old Gen? Not always. Some collectors special-case large allocations, so the exact path depends on the JVM and GC algorithm.
  • Tricky: If an object is in Old Gen, is it guaranteed to live forever? No. It is just more likely to be long-lived. Old-gen objects can still be collected when they become unreachable.

Common Mistakes:

  • Mistake: Saying Young Gen and Old Gen are just about size. Correction: They are about object lifetime and collection strategy, not only memory size.
  • Mistake: Confusing Old Gen with Metaspace. Correction: Old Gen is heap memory; Metaspace is separate and stores class metadata.
  • Mistake: Thinking every object must move from young to old. Correction: Many objects die in Eden and never get promoted.
  • Mistake: Treating System.gc() as a reliable control switch. Correction: It is a suggestion, not a guarantee.

Memory Hook: Think of Java objects as people in a nursery and a retirement home. Babies stay in the nursery because most leave quickly; only the survivors get moved to retirement.

Cheat Sheet:

  • Young Gen = new, short-lived objects.
  • Old Gen = long-lived, surviving objects.
  • Minor GC = collects Young Gen frequently.
  • Promotion = surviving objects move old.
  • Young GC is usually faster because less live data is scanned.
  • G1 and other modern collectors still follow the same lifetime idea, even if their internal layout differs.

Practice Tasks:

  • Run the demo with -Xms128m -Xmx128m -Xlog:gc* and observe how often young collections happen.
  • Modify the code so the cache keeps growing, then watch memory pressure increase.
  • Replace the static list with a request-local list and explain why that changes object lifetime.
Previous
Back to Questions←→to navigate
Next

Recommended Resources

Recommended Book

Cracking the Coding Interview

189 Programming Questions and Solutions

Recommended Book

Cracking the Coding Interview

189 Programming Questions and Solutions

import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; public class YoungVsOldGenerationDemo { // Objects kept here stay strongly reachable, so they are long-lived candidates. private static final List<Payload> longLivedCache = new ArrayList<>(); static class Payload { private final String name; private final byte[] data; Payload(String name, int sizeKb) { this.name = name; this.data = new byte[sizeKb * 1024]; } int touch() { // Touch the array so the object is clearly used. return data[0] + data[data.length - 1]; } @Override public String toString() { return name + "(" + (data.length / 1024) + "KB)"; } } public static void main(String[] args) throws InterruptedException { System.out.println("=== Short-lived allocations ==="); runShortLivedBurst(); System.out.println(); System.out.println("=== Long-lived allocations ==="); createLongLivedObjects(); System.out.println(); System.out.println("=== Weak reference edge case ==="); WeakReference<Payload> weak = createAndDropReference(); // System.gc() is only a hint, not a command. The JVM may ignore it or delay it. System.gc(); Thread.sleep(200); System.out.println("Weak reference cleared after GC hint? " + (weak.get() == null)); System.out.println(); System.out.println("=== Cache cleanup edge case ==="); if (longLivedCache.size() > 3) { System.out.println("Cache too large, removing oldest entries to reduce old-gen pressure."); while (longLivedCache.size() > 3) { longLivedCache.remove(0); } } System.out.println("Remaining cache entries: " + longLivedCache); } private static void runShortLivedBurst() { long checksum = 0; for (int i = 0; i < 20_000; i++) { // These objects are created and discarded quickly, which is exactly what Young Gen is optimized for. Payload p = new Payload("temp-" + i, 1); checksum += p.touch(); } System.out.println("Burst checksum: " + checksum); } private static void createLongLivedObjects() { for (int i = 1; i <= 5; i++) { // Keeping references in a static collection makes these objects survive many collections. Payload p = new Payload("cached-" + i, 256); longLivedCache.add(p); } System.out.println("Cache entries: " + longLivedCache); } private static WeakReference<Payload> createAndDropReference() { Payload p = new Payload("temporary-strong-ref", 512); WeakReference<Payload> ref = new WeakReference<>(p); // Once the strong reference is removed, the object becomes eligible for collection. // Whether it is reclaimed immediately depends on the JVM and memory pressure. p = null; return ref; } }