"How does Python's garbage collection work?"
Python GC is a mid-level Python interview question that tests whether you understand why Python is different from Java — reference counting is the primary mechanism, cycle collection is secondary. Getting this right signals language depth.
Primary mechanism: reference counting. Every Python object has a refcount; when it hits zero, memory is freed immediately. This means most objects are deallocated deterministically — no pause like JVM GC.
The problem reference counting can't solve: cycles. If a references b and b references a, neither refcount ever hits zero, even if nothing else points to them.
Solution: generational cycle collector (gc module). Periodically scans container objects for unreachable cycles and frees them. Three generations (0, 1, 2) — objects surviving collection get promoted to the next gen, which is scanned less often.
Trigger: gc runs when allocations minus deallocations crosses a threshold — default (700, 10, 10). Not time-based; tied to allocation pressure.
Implications: you can call gc.collect() to force cycle collection; gc.disable() is used in perf-sensitive code paths to avoid unpredictable pauses; weakref module breaks cycles intentionally (e.g., parent ↔ child object graphs).
Python's GC is a two-layer system. The primary layer is reference counting — every CPython object has a refcount field in its C struct, and every reference operation increments or decrements it. When the count reaches zero, the object is deallocated immediately, tp_dealloc is called, destructors run, and memory goes back to the allocator. This is fundamentally different from the JVM — most Python object cleanup is deterministic and synchronous, no waiting for a GC cycle. The downside: reference counting is per-op overhead on every assignment and function call, which is one reason CPython is slower than a JIT'd JVM. The other downside is reference counting cannot collect cycles. If object a holds a reference to b and b holds a reference to a, their refcounts include each other, so neither will ever hit zero even if nothing external points to them. Python solves this with a secondary generational cycle collector in the gc module. It periodically scans container objects — lists, dicts, classes, etc., anything that could hold references — and uses a mark-and-sweep-style algorithm to find unreachable cycles and free them. There are three generations. Newly allocated containers go into gen 0; objects that survive a collection are promoted to gen 1; surviving gen 1 survivors promote to gen 2. Higher generations are scanned less frequently, based on the assumption that long-lived objects are less likely to be garbage. Collection triggers when allocations minus deallocations cross a threshold — default is (700, 10, 10), meaning gen 0 runs after 700 net allocations, gen 1 runs every 10 gen-0 runs, and so on. It's not time-based — purely allocation-pressure driven. Practical implications: gc.collect() forces a full collection, useful before memory-sensitive operations. gc.disable() is sometimes used in performance-critical hot loops to avoid unpredictable pauses, with an explicit gc.collect() later. For "logical cycles" you know about in advance — common in parent-child object graphs like DOM trees or tree data structures — use weakref.ref or weakref.proxy to avoid creating the cycle at all, letting reference counting reclaim the objects deterministically.
Start with reference counting, then cycle collection — not the other way around. It reflects the actual architecture.
The "refcount is per-op overhead" point is a strong signal you understand CPython internals.
Mentioning weakref as the "escape hatch for known cycles" shows practical experience.
If you blank on the default threshold (700, 10, 10) in the interview, HireMe AI can surface the exact numbers.
Python uses refcounting first, collection second. JVM doesn't use refcounting because of multi-threaded atomic-increment overhead — Python has the GIL which makes refcount updates cheaper.
Yes — the GIL serializes refcount updates so they don't need atomic ops. Removing the GIL (ongoing in 3.13+ nogil work) requires atomic refcounts or alternative schemes.
Rarely. Only in tight loops where profiling shows gc pauses matter, and always re-enable and force collection afterward.
HireMe AI listens to your interview in real-time, detects questions, and generates instant answer suggestions — so you never freeze up again.
Try HireMe AI Free