Skip to main content

Refcounting, cycles, weakref

advanced20 min readLesson 136 of 169

Explain and diagnose memory behavior instead of fearing it.

Reference counting and the garbage collector

CPython's primary memory management is refcounting: every object counts its references; hitting zero frees it immediately (hence the instant __del__-less determinism CPython is known for).

Refcounting alone cannot free cycles (aโ†’bโ†’a). A supplementary cycle detector โ€” the generational gc module โ€” periodically scans container objects for unreachable cycles:

import gc, sys

class Node:
    def __init__(self):
        self.partner = None

a, b = Node(), Node()
a.partner, b.partner = b, a
del a, b                       # refcounts never hit zero โ€” cycle!
gc.collect()                   # cycle detector frees them

Practitioner takeaways:

  • sys.getrefcount(x) shows the count (always +1 for the argument itself).
  • Most "memory leaks" in Python are reference leaks: caches, registries, closures, or loggers holding objects forever. Find them with gc.get_referrers(obj) โ€” who still points at this?
  • gc.garbage collects objects the collector could not free (usually __del__-bearing cycles) โ€” its growth is a design smell.
  • weakref lets a cache reference objects without keeping them alive โ€” the standard fix for registry-induced leaks.
  • gc.disable() can speed allocation-heavy batch jobs slightly, at the cost of cycle leaks โ€” measure before adopting.

Now practice

Memory PracticeWeakrefs that let go: a cache that never leaks, verified with gc counts.1 challenge ยท ยท ~20 min