Runtime · intermediate

Garbage collection

Garbage collection is runtime-managed reclamation of storage that a program can no longer use under the collector's model. Tracing collectors reclaim objects unreachable from roots; reference-counting systems can reclaim objects when counts reach zero and may use separate cycle detection. Algorithms, timing, and pause behavior vary by runtime.

Why it matters

GC removes many manual deallocation errors but still affects latency, throughput, memory footprint, and object lifetime. It also does not replace explicit management of files, locks, transactions, or network connections.

Mental model

How to reason about garbage collection

A tracing collector starts from roots such as active frames, globals, and runtime handles, then determines which objects remain reachable. A reference-counting collector instead tracks ownership counts and needs additional handling for cycles. In either model, objects the runtime still considers live can remain as logical memory leaks.

Analogy

A collector clears warehouse items that cannot be reached from any active inventory record. Items mistakenly left on a live manifest stay in storage even if nobody intends to use them again.

Examples

See the boundary, not just the happy path

Worked example · Drop the final application reference

cache.remove(key)

If no roots or other reachable objects refer to the removed object, it becomes eligible under a tracing model. Eligibility does not promise immediate reclamation or finalization.

Worked example · Collect an unreachable cycle

a.peer = b; b.peer = a; then all external references are removed

A tracing collector can discover that neither object is reachable from roots despite their references to each other. Simple reference counting alone needs additional cycle handling.

Useful contrast · Close external resources explicitly

with open('report.txt') as file: process(file)

The context manager closes the file deterministically when the block exits. Waiting for garbage collection would hold an operating-system resource for an unspecified duration.

Common mistakes

Misconceptions to remove early

Assuming garbage collection prevents all memory leaks

An accidentally growing cache, listener list, global collection, or retained closure keeps objects reachable. The collector correctly preserves them even though the application no longer needs them.

Using finalizers for timely cleanup

Collection and finalization timing can be delayed or omitted at process exit, and ordering is difficult. Use deterministic cleanup constructs for scarce external resources.

Quick check

Can you predict the result?

1. Can two objects that reference each other be garbage-collected by a tracing collector?
  • Yes, if neither is reachable from the collector's roots.
  • No, every cycle is permanently reachable.
  • Only if both objects contain no fields.
Answer: Yes, if neither is reachable from the collector's roots.
2. Why should a file be closed explicitly in a garbage-collected language?
Answer: Garbage-collection timing is nondeterministic, while the operating-system descriptor is a scarce resource that should be released promptly.

Keep building

Authoritative references

Make the idea retrievable.

Study this concept with spaced repetition, next to the commands where you use it.

Get Terminaster