Back to Memory Management & GC
Q6Question 6 of 21

How does garbage collection work in Java?

Key Concepts
  • GC automatically reclaims memory from objects that are no longer reachable from GC roots
  • Mark phase: trace from GC roots, mark all reachable objects as LIVE
  • Sweep/Compact: reclaim memory from unmarked (dead) objects, optionally compact to reduce fragmentation
  • Generational hypothesis: most objects die young → young gen collected frequently, old gen rarely
  • Young GC (Minor): fast, collects Eden + Survivors. Full GC: slow, collects entire heap
  • GC runs on its own schedule – you cannot force it (System.gc() is only a suggestion)

Definition

GC traces from roots, marks live objects, and reclaims dead ones. Most objects die young (generational hypothesis), so the young generation is collected frequently and cheaply.

GC algorithm:

  1. Mark: Start from GC roots (stacks, statics). Trace all references. Mark reachable objects.
  2. Sweep: Free memory of unmarked (dead) objects.
  3. Compact (optional): Move surviving objects together to eliminate fragmentation.
  4. Generational: Young Gen (short-lived) collected often. Old Gen (long-lived) collected rarely.

The bank vault (heap) periodically audits which safety deposit boxes (objects) are still claimed (reachable). Unclaimed boxes are emptied (garbage collected). Recently opened boxes (young gen) are audited frequently because most are temporary.

Understanding the Concepts

Generational heap

DIAGRAM
  Heap:
  ┌─── Young Generation ───────────┐  ┌─── Old Generation ──┐
  │  Eden  │ Survivor 0 │ Survivor 1│  │  Long-lived objects │
  │  (new objects land here)        │  │  (survived many GCs) │
  └─────────────────────────────────┘  └─────────────────────┘

  Minor GC: collects Young Gen (fast, ~10ms)
  Full GC:  collects entire heap (slow, ~100ms-seconds)

Object lifecycle

  1. new Account() → allocated in Eden.
  2. Minor GC: if still reachable, moved to Survivor space. Age incremented.
  3. After N Minor GCs (default 15), promoted to Old Gen.
  4. Full GC: Old Gen collected when full or explicitly requested.

Common GC algorithms

| GC | Type | Best for |
|---|---|---|
| G1 | Default (Java 9+) | General-purpose, balanced |
| ZGC | Low-latency | <1ms pauses, large heaps |
| Shenandoah | Low-latency | Similar to ZGC |
| Parallel | Throughput | Batch processing |
| Serial | Single-thread | Small heaps, containers |

What should a senior engineer know?

  • GC logs: -Xlog:gc* (Java 9+) or -verbose:gc (legacy). Essential for tuning.
  • GC pause time goal: -XX:MaxGCPauseMillis=200 (G1 target).
  • Memory leaks in Java: Objects that are reachable but no longer needed (e.g., growing static collections).

What are common mistakes?

A common mistake is assuming that calling System.gc() guarantees garbage collection. The JVM treats this as a suggestion, not a command.

Wrong approach:

JAVA
package com.bank.service;

public class AccountCleanup {
    public void cleanupOldAccounts() {
        // WRONG: relying on System.gc()
        oldAccounts = null;
        System.gc();  // No guarantee this runs
        System.out.println("Memory freed");  // May not be true
    }
}

Correct approach:

JAVA
package com.bank.service;

public class AccountCleanup {
    public void cleanupOldAccounts() {
        // CORRECT: let the GC do its job, just remove references
        oldAccounts.clear();
        oldAccounts = null;
        // Do not call System.gc() in production
        // Monitor with -verbose:gc or JFR instead
    }
}

Another common mistake is holding references to objects that are no longer needed, which prevents garbage collection and causes memory leaks in long-running banking applications.

What are the edge cases?

Edge cases in memory management can cause unexpected behavior in banking applications.

JAVA
package com.bank.edge;

public class MemoryEdgeCases {
    public static void main(String[] args) {
        // Edge case 1: large arrays get allocated directly in Old Gen
        byte[] largeBuffer = new byte[10 * 1024 * 1024]; // 10 MB
        // This skips Eden and goes straight to Old Gen

        // Edge case 2: String.intern() can cause memory issues
        // if you intern millions of unique transaction IDs
        for (int i = 0; i < 1_000_000; i++) {
            String txnId = ("TXN-" + i).intern(); // Bad: fills String Table
        }

        // Edge case 3: SoftReference behavior changes under memory pressure
        // Objects may be collected sooner than expected
    }
}
  • Humongous objects in G1. Objects larger than half a G1 region are allocated as humongous objects, bypassing the normal Eden allocation path.
  • Metaspace leaks. Dynamic class generation (e.g., in ORM frameworks) can leak class metadata if classloaders are not properly garbage collected.
  • Direct ByteBuffer. Off-heap memory allocated with ByteBuffer.allocateDirect() is not counted in -Xmx and can cause OutOfMemoryError: Direct buffer memory.

What are common interview follow-up questions?

Interviewers often follow up with these related questions:

  • How does this concept apply to a high-throughput banking transaction system?
  • What are the performance implications in a production environment?
  • How would you debug issues related to this concept?
  • What tools would you use to monitor this in production?
  • How does this behave differently in Java 8 vs Java 17+?

When answering follow-up questions, always relate your answer back to practical experience. For example, at National Bank of India, Rajesh debugged a production issue related to this concept by using JFR recordings and heap dumps. Providing concrete examples from banking systems shows the interviewer that you understand both the theory and the practice.

Visual Overview

DIAGRAM
  new Account() → Eden
    │ Minor GC
    ▼
  Reachable? → Survivor (age++)
  Not reachable? → freed
    │ age > threshold
    ▼
  Old Generation
    │ Old Gen full
    ▼
  Full GC (slow, STW)

  GC types: G1 (default), ZGC (low-latency), Parallel (throughput)

Key Takeaway

GC automatically reclaims unreachable objects. It traces from GC roots, marks live objects, and frees the rest. The generational hypothesis (most objects die young) enables fast, frequent young generation collection and rare, slower old generation collection.

One sentence to remember: GC marks reachable objects and frees the rest – young gen is collected often and cheaply, old gen rarely and expensively.

---

Share
Use ← → arrow keys to navigate