What Is Garbage Collection in Software?

Software memory objects being sorted between active and reclaimable regions

Garbage Collection Explainer

Garbage collection is automatic memory management that reclaims storage occupied by objects a program can no longer use. An application allocates objects while it runs and keeps references to the ones it needs. Instead of requiring the programmer to free every object manually, a runtime periodically determines which allocations remain reachable from the program’s active state. Unreachable objects are garbage because no valid sequence of references can lead to them. Their space can be returned to an allocator or reused for later objects.

The search starts from roots. Roots commonly include references in thread stacks, processor registers, static fields, and runtime data structures. The collector traces from those roots through each object’s reference fields and marks everything it can reach. Any object not found by this traversal is unreachable, even if it participates in a cycle with other unreachable objects. That is an advantage over simple reference counting, which can reclaim an object when its count reaches zero but needs additional handling for isolated cycles whose objects still point to one another.

After identifying live objects, a collector must recover space. A mark-sweep collector marks reachable objects and places unmarked regions on a free list. A compacting collector moves live objects together so free space becomes contiguous, updating references to their new locations. Copying collectors move survivors from one region to another and discard the old region wholesale. Each method balances work, locality, fragmentation, and the cost of moving objects. Some objects may be pinned because native code or hardware expects a stable address.

Many runtimes use generations because most newly allocated objects become unreachable quickly while objects that survive several collections tend to live longer. A small young generation can be collected frequently, copying only survivors. Longer-lived objects are promoted to an older region that is scanned less often. Write barriers record references from older objects to younger ones, so a young collection does not have to inspect the entire heap. This generational hypothesis is a useful workload pattern, not a rule that every program follows.

Collection work can stop application threads, run concurrently with them, or mix both approaches. A stop-the-world phase gives the collector a stable view but creates a pause. Concurrent marking reduces pause time, but barriers and coordination add CPU cost, and some brief pauses usually remain. Incremental collectors divide work into smaller portions. Runtime options may prioritize throughput, low latency, small memory footprint, or predictable pauses. No setting removes the underlying need to discover reachability and make free space available faster than the program consumes it.

Automatic reclamation prevents many dangling-pointer and double-free errors, but it does not prevent every leak. A cache, listener, global collection, or accidental reference can keep an object reachable forever even when the application no longer needs it. Finalizers and cleanup callbacks have uncertain timing and should not be the primary way to release files, locks, or network connections; explicit lifetime controls are safer for those resources. Developers monitor allocation rate, live-set size, pause duration, promotion, and heap growth, then reduce unnecessary retention or select an appropriate collector. Garbage collection’s real promise is managed reachability: the runtime can safely reuse memory that is provably inaccessible, while performance still depends on object lifetimes, allocation patterns, heap size, and the collector’s tradeoffs.

Heap sizing changes the balance. A larger heap can postpone collections and give a concurrent collector more room, but it consumes memory and can increase the amount of live data or address space the runtime must manage. A very small heap triggers frequent work and may prevent the application from making progress during bursts. Allocation profiling often finds a better remedy than tuning alone: removing temporary objects, bounding caches, and shortening reference lifetimes reduce both memory use and collection pressure. Capacity tests should include steady traffic and sudden peaks because a collector that looks excellent in an average benchmark may struggle when allocation briefly outruns reclamation.

Garbage collection traces objects reachable from roots and reclaims allocations that can no longer be reached. Key terms include root, reference, reachability, mark, sweep, compaction, copying, generation, promotion, write barrier, pause, and live set.

Yes. An object is not collectible while any live reference reaches it. Unbounded caches, registered listeners, global collections, or unintended reference chains can retain objects that the application no longer needs.

Some phases need a consistent view of roots, references, or object locations. Concurrent and incremental designs shorten pauses by doing more work beside the application, but barriers and coordination add their own overhead.

Explore more "Explainers"

Discover additional explainers across politics, science, business, technology, and other fields. Each explainer breaks down a complex idea into clear, everyday language—helping you better understand how major concepts, systems, and debates shape the world around us.