Garbage Collection
Study how the JVM finds unreachable objects and reclaims heap memory safely.
Garbage Collection Basics
Garbage collection (GC) is the JVM's automatic process for identifying heap objects that are no longer reachable under the applicable runtime rules and reclaiming their memory. GC manages Java heap memory; it is not a replacement for closing files, sockets, or database connections.
Assigning null removes a reference but does not immediately collect the object. System.gc() is only a request or suggestion; the JVM does not guarantee collection of a particular object. JVM memory also includes thread stacks, native memory, class metadata, compiled code, and runtime structures, not just heap objects.
public class GCDemo {
public static void main(String[] args) {
Object first = new Object();
Object second = new Object();
first = null; // may become unreachable
second = null; // may become unreachable
System.out.println("References removed");
}
}Reachability Analysis
Reachability analysis determines which objects can be reached by traversing references from GC roots. An unreachable object can be eligible for reclamation, though reclamation does not occur immediately.
Two nodes that refer to each other form a cycle, but if no GC root can reach either, a tracing collector can reclaim both. Objects do not stay alive merely because they refer to one another.
class Node { Node next; }
Node first = new Node();
Node second = new Node();
first.next = second;
second.next = first;
first = null;
second = null;GC Roots
GC roots are the JVM-defined starting points used by a tracing collector. Typical sources include references in active thread execution state, relevant static fields, JNI references, and other live runtime structures. The precise root set depends on the JVM and collector.
Static fields and growing collections can unintentionally retain objects. Such retention can cause a Java memory leak even though the JVM has garbage collection.
import java.util.ArrayList;
import java.util.List;
class CacheLeakDemo {
static final List<byte[]> cache = new ArrayList<>();
public static void main(String[] args) {
while (true) {
cache.add(new byte[1024 * 1024]);
}
}
}Reference Counting
Reference counting tracks how many references point to an object. In a simple model, a count that reaches zero means the object is reclaimable. Simple reference counting has difficulty with cycles, because objects in a cycle keep each other's counts above zero.
Ordinary HotSpot garbage collection uses tracing and reachability techniques rather than simple reference counting as its general-purpose heap collection method.
Mark-Sweep Algorithm
Mark-sweep has two stages. First, the collector starts from roots and marks reachable objects. Second, it scans memory and reclaims space belonging to unmarked objects. Because live objects do not necessarily move, free space can remain fragmented.
Advantages: unreachable cycles are reclaimed and live objects need not all be moved. Disadvantage: the remaining free space may be fragmented.
Mark-Compact Algorithm
Mark-compact identifies live objects and then moves them so they occupy a compact region. This reduces fragmentation, but moving objects and maintaining valid references requires work.
Modern collectors may compact selected regions or use other relocation strategies rather than compacting the entire heap each time.
Copying Algorithm
A copying collector moves live objects from a source region into a destination region. Once survivors are evacuated, the source region can be reused. This is effective when most objects in the source region are dead, but space must be available for survivors.
Copying collectors must keep references to moved objects correct. Generational collectors often use copying or evacuation for young objects, though implementations vary.
| Feature | Mark-Sweep | Mark-Compact | Copying |
|---|---|---|---|
| Identifies live objects | Yes | Yes | Yes |
| Reclaims unreachable objects | Yes | Yes | Yes |
| Moves survivors | Not necessarily | Yes | Yes |
| Reduces fragmentation | Not inherently | Yes | In evacuated region |
| Needs destination space | Not inherently | Depends on approach | Yes |
Generational GC
Generational GC uses the observation that many objects die soon after creation while some live a long time. In the traditional HotSpot model the heap is a young generation, shown as Eden and two survivor spaces, and an old generation.
Objects are often allocated in Eden, survivors may move between survivor spaces, and sufficiently long-lived objects may be promoted. Exact rules depend on the collector; not every modern collector uses this literal layout.
Minor GC
Minor GC traditionally means a collection focused on the young generation. The collector identifies live objects, reclaims dead ones, and may evacuate survivors to survivor regions or promote them.
Young collections are efficient when most young objects are dead, but a minor collection is not guaranteed to be short. Pause duration depends on live data, reference processing, collector design, hardware, and workload. The term is not used identically by all collectors.
Major GC
Major GC commonly refers to an old-generation collection or one focused on long-lived objects. Terminology differs among collectors and tools, so interpret it using the collector documentation and GC logs.
If long-lived objects are no longer reachable, an old-generation collection may reclaim them. Objects still referenced from caches or static fields remain reachable.
Full GC
Full GC conventionally describes a broad collection involving the entire Java heap or a wide portion of managed memory. Depending on the collector it can involve marking, reclamation, compaction, or other runtime work.
Triggers vary: allocation pressure, insufficient space, explicit GC requests if honored, or collector-specific recovery needs. System.gc() does not guarantee a Full GC.
| Traditional term | Common interpretation | Caution |
|---|---|---|
| Minor GC | Young-generation collection | Not universal terminology |
| Major GC | Old-generation-focused collection | Meaning varies by collector |
| Full GC | Broad or full-heap collection | Scope and pause behavior are implementation-dependent |
Stop-The-World Events
A Stop-The-World (STW) event is a period when the JVM suspends application threads for a runtime operation. GC may need pauses to inspect a stable view of state, update references, evacuate objects, compact memory, or finish a phase. Modern collectors do substantial work concurrently but may still use short STW phases.
Long pauses increase response latency. The threads stopped, pause duration, and phases depend on collector and configuration. Safepoints are one JVM mechanism used to coordinate some operations.
A useful diagnostic starting point on modern Java releases is the unified GC log. Tune from observed workload data rather than from the number of collections alone.
| Collector | General design goal |
|---|---|
| Serial GC | Simple design with a single GC thread; suits small workloads |
| Parallel GC | Parallel collection work, focused on throughput |
| G1 GC | Heap regions and pause-time goals balance throughput and latency |
| ZGC | Low latency; most expensive work is concurrent |
java -Xlog:gc* MyApplicationQuick Review and Interview Questions
Can Java applications have memory leaks? Yes, objects no longer useful can stay reachable through static fields, caches, collections, or listener registrations.
Can a tracing collector reclaim circular references? Yes, if no GC root can reach the cycle.
Does System.gc() guarantee collection? No, it is a request.
Are Minor GC and Major GC universal JVM terms? No, meanings vary by collector and tool.
Is every GC phase stop-the-world? No, some collectors do substantial work concurrently but may still pause.
How do compressed OOPs reduce memory use? They encode many heap references in 32 bits instead of 64 in supported HotSpot configurations.
What makes a GC pause long? Live-data volume, collector strategy, allocation rate, reference processing, and work in paused phases.
How do you investigate GC performance? Inspect GC logs, heap occupancy, allocation patterns, and application latency together.