Garbage Collection

How GC Decides What to Free

The garbage collector frees objects that are no longer reachable from a GC root: local variables on thread stacks, static fields, active threads, JNI references. Reachability, not reference counting, so circular references are collected fine.

GC roots ──► Order ──► Customer          reachable: kept
          └─► Cart  ──► Item
                 X  ──► OldSession ◄──► OldToken   unreachable (even with a cycle): freed

Generational Heap

Most objects die young (request DTOs, temporary strings). So the heap is split into generations:

  1. New objects go to Eden.
  2. A minor GC copies live Eden objects to a Survivor space; dead ones are dropped for free.
  3. Objects that survive several minor GCs are promoted to the Old generation.
  4. A major / full GC cleans the old generation — slower, longer pauses.

Collectors

CollectorFlagGood for
Serial-XX:+UseSerialGCtiny heaps, single-core containers
Parallel-XX:+UseParallelGCbatch jobs: max throughput, pauses OK
G1 (default since Java 9)-XX:+UseG1GCgeneral servers, pause target -XX:MaxGCPauseMillis=200
ZGC (generational in 21)-XX:+UseZGC -XX:+ZGenerationalbig heaps, sub-millisecond pauses
Shenandoah-XX:+UseShenandoahGClow pause (OpenJDK builds)

Example

Turn on GC logging to see collections:

java -Xms512m -Xmx512m -Xlog:gc -jar shop.jar

Example output

[0.012s][info][gc] Using G1
[3.481s][info][gc] GC(0) Pause Young (Normal) (G1 Evacuation Pause) 25M->4M(512M) 3.211ms
[7.902s][info][gc] GC(1) Pause Young (Normal) (G1 Evacuation Pause) 31M->6M(512M) 2.874ms

Reference Types

TypeCollected whenUse
Strong (normal)never while reachableeverything
SoftReferencememory is lowmemory-sensitive caches
WeakReferencenext GC if only weakly reachableWeakHashMap, listeners
PhantomReferenceafter finalization, for cleanupCleaner API

Note: System.gc() is only a hint. Never rely on it. finalize() is deprecated; use try-with-resources or Cleaner.