Memory Modelcritical

Reference Counting

Every Python object has a reference count. When it reaches zero, memory is freed immediately.

Memory anchor

ref-COUNT = a library book's checkout card. Each borrower adds a tally. The book goes back on the shelf (freed) only when the last borrower returns it — zero tallies left.

Expected depth

sys.getrefcount(obj) returns the current count (always at least 1 because the getrefcount call itself creates a reference). Each assignment, function argument pass, or container append increments the count. del x decrements it. When the count hits 0, __del__ is called and the memory is freed. This is deterministic and fast for most cases.

Deep — senior internals

Reference counting is O(1) per operation — no GC pause for non-cyclic objects. But it can't handle cycles (A → B → A both have count > 0 even if nothing external references them). The cyclic GC handles this separately. Reference counting also interacts with the GIL — the GIL protects reference count modifications from data races. In CPython, every object starts with ob_refcnt in its header. The __del__ finalizer may resurrect an object, which can cause subtle bugs.

🎤Interview-ready answer

Python's primary memory management is reference counting — each object tracks how many references point to it. When the count hits 0, memory is freed immediately. sys.getrefcount() lets you inspect it. This gives deterministic cleanup for most objects. The weakness is cycles — if A references B and B references A, neither count reaches 0, so the cyclic garbage collector handles those separately.

Common trap

del x does NOT immediately free memory. It only decrements the reference count. Memory is freed only when the count reaches 0. If anything else holds a reference, the object lives on.

Related concepts