Chaturmind
LearnDSASystem DesignDevOpsEngineering GrowthBlog
Start learning
Chaturmind

Structured learning paths for engineers who want to go deep. Written by practitioners.

Learn

  • Java
  • DSA
  • System Design
  • Spring Boot
  • AI / ML
  • DevOps
  • Engineering Growth

Company

  • Blog
  • Contact

Legal

  • Privacy Policy
  • Terms of Service

© 2026 Chaturmind. All rights reserved.

Built for engineers who want to go deep.


← Java Core Fundamentals

Object-Oriented Programming

  • Classes and Objects
  • Inheritance and Polymorphism
  • Interfaces and Abstract Classes

Collections Framework

  • List, Set, and Map
  • Generics
  • Collections Framework Recap
  • HashMap Deep Dive
  • TreeMap & LinkedHashMap
  • Iterators & Modification Semantics

Exceptions & Best Practices

  • Exception Handling
  • equals() and hashCode()
  • String Manipulation

JVM Internals & Memory Management

  • JVM Memory Areas
  • Garbage Collection Fundamentals
  • Modern Garbage Collectors
  • Memory Leaks in Java
  • GC Tuning & Diagnostics
Chaturmind
← Java Core Fundamentals

Object-Oriented Programming

  • Classes and Objects
  • Inheritance and Polymorphism
  • Interfaces and Abstract Classes

Collections Framework

  • List, Set, and Map
  • Generics
  • Collections Framework Recap
  • HashMap Deep Dive
  • TreeMap & LinkedHashMap
  • Iterators & Modification Semantics

Exceptions & Best Practices

  • Exception Handling
  • equals() and hashCode()
  • String Manipulation

JVM Internals & Memory Management

  • JVM Memory Areas
  • Garbage Collection Fundamentals
  • Modern Garbage Collectors
  • Memory Leaks in Java
  • GC Tuning & Diagnostics
HomeLearnJavaJava Core FundamentalsJVM Internals & Memory Management
✓ FreeIntermediate· 9 min read

Garbage Collection Fundamentals

The generational hypothesis behind young/old generation splits, minor vs major GC, mark-sweep-compact, and what actually counts as a GC root.

Published September 23, 2026


Garbage Collection Fundamentals

The generational hypothesis

Empirically, in most applications, most objects die young — a request-scoped object, a loop's temporary variable, an intermediate stream result. Long-lived objects (caches, singletons, connection pools) are comparatively rare. The JVM's heap is deliberately split into generations to exploit this pattern: collect the young generation frequently and cheaply (most of it is garbage, so a collection reclaims a lot fast), and collect the old generation rarely and expensively (it's mostly still-live data, so scanning it often would be wasted effort).

Young generation: Eden + two Survivor spaces

[ Eden ] [ S0 ] [ S1 ]   <- Young Generation
[        Old Generation            ]

New objects are allocated in Eden. When Eden fills up, a Minor GC runs: live objects in Eden are copied into one of the two Survivor spaces (S0/S1 — only one is "active" at a time; the other stays empty until the next collection). Each time an object survives a Minor GC, its age counter increments; after surviving enough collections (the survival threshold, tunable), it gets promoted to the old generation — the assumption being that anything that's survived this many young-gen collections is probably going to live a while longer, so it's cheaper to stop re-copying it every cycle.

Minor GC vs Major/Full GC

  • Minor GC: collects only the young generation. Cheap and frequent — because young gen is small and mostly garbage, a minor GC typically pauses the application for only milliseconds.
  • Major/Full GC: collects the old generation (and often young gen along with it). Expensive and infrequent — old gen is large and mostly live, so a full scan-and-compact takes meaningfully longer, and a Full GC pause is the kind of event that shows up as a visible latency spike in production monitoring.

This cost asymmetry is exactly why GC tuning (see GC Tuning & Diagnostics) so often focuses on avoiding unnecessary promotions and Full GCs — a young-gen-heavy allocation pattern that rarely needs a Full GC is dramatically cheaper than one that promotes aggressively and triggers frequent old-gen collections.

Mark-sweep-compact: the algorithm underneath

Three phases, run in sequence during a collection:

  1. Mark — starting from GC roots (see below), traverse every reachable object, marking each one as "live."
  2. Sweep — reclaim the memory occupied by every unmarked (unreachable, i.e. garbage) object.
  3. Compact — slide the remaining live objects together, eliminating the gaps left by swept objects, so future allocations can use one contiguous free region instead of hunting through fragmented free space.

Compaction specifically is what prevents fragmentation — without it, a heap could have plenty of total free space scattered in small, non-contiguous chunks, none large enough to satisfy a new allocation request, even though the sum of free space would technically be sufficient.

GC roots: what counts as a starting point for reachability

An object is "live" if it's reachable, by some chain of references, from a GC root — anything not reachable from a root, no matter how large or recently created, is garbage. GC roots include:

  • Active thread stacks — any local variable currently in scope on any running thread's call stack.
  • Static fields — class-level state referenced by a loaded class is always reachable as long as that class stays loaded, which is exactly why unbounded static collections are the classic memory leak (see Memory Leaks in Java) — a static field is a permanent GC root, so anything it transitively references can never be collected, no matter how unreachable it would otherwise be.
  • JNI references — objects referenced from native code via the Java Native Interface.

Understanding GC roots precisely is what makes heap-dump analysis (see GC Tuning & Diagnostics) tractable — a leak-suspect report works backward from a suspiciously large object, finding the dominator chain of references back to a GC root, which is usually where the actual leak-causing code lives.

Follow-up questions this topic invites — and their answers

Q: Why two Survivor spaces instead of one? A: A Minor GC needs somewhere to copy both the objects currently in the active Survivor space (that haven't been promoted yet) and the newly-surviving objects from Eden, without overwriting either set mid-collection — using two spaces and alternating which one is "active" (a copying collector technique) avoids needing a separate temporary buffer, and as a side effect, it also naturally compacts the young generation on every single Minor GC.

Q: Does every GC algorithm use mark-sweep-compact exactly as described? A: Mark-and-sweep (with or without compaction) is the conceptual baseline nearly every collector builds on, but modern collectors (see Modern Garbage Collectors) add region-based collection, concurrent marking, or incremental/parallel phases on top of this baseline to reduce pause times — the mark/sweep/compact vocabulary still applies, but the how differs significantly by collector.

Q: If an object is referenced only by another garbage object, is it also garbage? A: Yes — reachability is transitive from GC roots. If object A is garbage (unreachable from any root) and A is the only thing referencing object B, then B is also unreachable (nothing traces a live path to it) and gets collected in the same pass, even though nothing explicitly marked B as garbage directly.

Q: Why does the survival threshold exist instead of promoting every object that survives even one Minor GC? A: Promoting too eagerly fills the old generation with objects that might still die soon after, which wastes old-gen space and triggers more (expensive) old-gen collections than necessary — requiring several survived cycles before promotion is a bet that objects surviving that long are genuinely likely to be long-lived, filtering out the "survived by coincidence, still short-lived" cases.

Previous

JVM Memory Areas

Next

Modern Garbage Collectors

AI Tutor

Lesson: Garbage Collection Fundamentals

Quick actions

AI responses can be inaccurate. Verify critical information.