Operating Systems intermediate LIVE DEMO
♻️

Garbage Collection Mark-Sweep-Compact Visualization

Step through managed-runtime garbage collection: allocation, GC roots, reachability, stop-the-world marking, sweeping, compaction, leaks, and recovery.

garbage collectionmemory managementheapmark-sweepcompactionmemory leakJavavisualization
Interactive Demo

Continue with the guided workspace

Use the paired workspace to connect this guide's mental model with live component state, visible signals, and the outcome each step or scenario is meant to prove.

Garbage collection (GC) is the automated process of managing a program’s dynamic memory allocation. Rather than requiring developers to manually allocate and free memory, managed runtimes (like Java, .NET, or V8) run a background garbage collector.

Mental Model

Understanding GC requires visualizing the heap as an object reference graph rooted in the execution stack. Runtimes trace reachability starting from β€œGC Roots”—such as active stack frames, local variables, or static fieldsβ€”and follow all reference paths. Any object that can be reached from these roots is considered live and must be preserved. Any object that is no longer reachable is dead space, which the collector sweeps and optional compacts to reclaim contiguous memory for future allocations.

Components and Why They Exist

Application Thread

Executes the main user application logic (mutator) that allocates memory and creates object references. Performs the core program execution, dynamically requesting memory from the heap as needed. In the demo, watch it transition to a paused (red) status during the stop-the-world pause.

GC Roots

The starting points for reachability tracing, anchoring live objects via active stack frames, local variables, and static fields. Serves as the trusted source of active references; any object unreachable from these roots is considered garbage. In the demo, watch how live objects remain linked directly or indirectly to the GC Roots node.

Heap Space

The dedicated pool of dynamic memory where all objects are allocated and stored during application execution. Manages memory pages, stores object instances, and tracks overall memory usage, utilization percentage, and fragmentation. In the demo, observe the total memory fill up and then drop after sweeping and compaction.

Object Graph

Models the network of references and relationships linking parent and child objects in memory. Represents the paths that the garbage collector traverses starting from the roots to determine reachability. In the demo, look at the nodes change color (from white to green for live/marked, or red/unreachable for dead).

Mark Queue

Tracks the traversal frontier during the marking phase to implement tri-color marking or breadth-first search. Holds references to objects that have been discovered but whose outgoing references have not yet been fully scanned. In the demo, watch object references queue up and get processed during the Mark phase.

Sweeper

Reclaims memory occupied by dead (unreachable) objects to make it available for future allocations. Iterates through the heap and returns the address spaces of unmarked objects back to the free list. In the demo, watch dead objects vanish and leave behind holes (fragmentation).

Compactor

Solves memory fragmentation by ensuring free memory is contiguous rather than scattered in small holes. Shifts surviving objects to one end of the heap and updates all references pointing to those moved objects. In the demo, watch fragmented survivors sliding together to form a contiguous block.

Free List

Tracks available blocks of memory that can be quickly allocated to new objects. Maintains pointers to free memory chunks, allocating them to the mutator and updating when the sweeper reclaims memory. In the demo, watch it update with reclaimed memory addresses.

Leak Root

Illustrates how memory leaks occur when application code holds onto unused references. Anchors objects in the reachability graph, preventing the collector from reclaiming them even if they are no longer logic-wise needed. In the demo, watch how leaking objects survive sweep cycles even though the application is done using them.

Pause Meter

Monitors and measures Stop-The-World (STW) pauses to track application responsiveness and latency. Records the duration and frequency of GC pauses that halt mutator execution. In the demo, watch the pause indicator light up and count pauses when mutator threads are stopped.

Edge Cases and Misconceptions

  • Misconception: Unreferenced objects are freed immediately: In trace-based garbage collection, objects are only reclaimed when a collection cycle runs, not the instant they lose references.
  • Misconception: Managed code cannot leak memory: Runtimes only prevent β€œmemory leaks” in the sense of lost pointers. If a program keeps a reference to an unused object in a static collection, cache, or long-lived listener, it remains reachable and will never be collected.
  • Edge Case: Stop-The-World (STW) Pauses: During tracing and compaction, mutator threads must be stopped. If heap memory is large or object references are complex, these pauses can cause application latency spikes (GC pauses).

Open the Garbage Collection simulator sandbox after the walkthrough when you want to experiment with high allocation, manual GC, leak injection, compaction toggles, and OOM pressure.

Common Questions

Why can a garbage collector not reclaim a memory leak?

A managed-runtime leak is often still reachable from a root or long-lived container, so the collector must preserve it even if the application no longer needs it.

What causes stop-the-world pauses?

Collectors sometimes pause application threads to scan roots, trace references, or move objects while maintaining a consistent heap view.

What is the difference between sweeping and compaction?

Sweeping marks memory locations of dead objects as free, leaving the heap fragmented. Compaction moves live objects next to each other to create a single contiguous block of free memory.

How does reference counting differ from tracing garbage collection?

Reference counting reclaims objects as soon as their reference count drops to zero, but fails to handle cyclic references. Tracing starts from roots and naturally handles cyclic references because unreachable cycles are never traversed.