Unit 3.9 · about 2 h
18 / 324Reference counts, cycle collection and weak references
Caches and listeners hold objects past their welcome. Lifetime reasoning decides between a leak and a dangling callback.
- explain
- measure
You can now
- Explain reference counting and cycle collection, and predict when each frees an object.
- Use weak references for caches and callbacks without creating ownership bugs.
- Measure collection behavior with
gc.collect,gc.get_countandsys.getrefcounton a diagnosed case.
Covers
- Reference counts, cycle collection and weak references
Study, in this order
4 steps
- Objects and garbage collectionPython language reference
Section 3.1: refcounting with delayed cycle detection; never depend on immediate finalization; close files explicitly
- The cycle collectorgc - cycle garbage collector
collect,get_count,get_threshold,garbageanddisable/enableDepth · The generations changed within 3.14: 3.14.0 to 3.14.4 run an incremental collector (
gc.get_threshold()reads(2000, 10, 0)on 3.14.4), and the docs record that 3.14.5 restores the three 3.13 generations. Readgc.get_threshold()on your interpreter before reasoning about generations. - Weak referencesweakref - weak references
Weak-reference objects with callbacks; which types refuse weakrefs; the
WeakValueDictionarypattern - Finding leaksStas' Python Cookbook - selected path
Profiling CPU and Memory: Finding leaks (
gc.collect,gc.garbage) with the refcounting one-liner;tracemallocabove it for sizing
Focus on
- CPython frees by refcount immediately and collects cycles later. A self-referencing object with
__del__is still collected since Python 3.4 by PEP 442. sys.getrefcountcounts its own argument, and CPython 3.14 borrows references when it loads locals, so one fresh object reads 2 at module level and 1 inside a function. The docs promise nothing beyond 0 or 1; compare readings taken in one context, never absolutes.weakref.reffails onlistanddictinstances (subclasses can opt in), ontupleandint, and on slotted classes without__weakref__; sets and frozensets support it. Caches wantWeakValueDictionary, not manual callback books.gc.garbageholds objects the collector refused; an empty list aftergc.collect()proves the run happened, not that nothing leaked.
Reproduce closed-book
__del__ method and a weakref callback, delete both names, and, with gc.disable() first, show that nothing runs until gc.collect(), which fires the callback and both __del__ methods. Then show sys.getrefcount on a fresh object reads 2 at module level and 1 inside a function on CPython 3.14.4.Traps
- Depending on
__del__timing. Collection order is unspecified, so close resources explicitly. - Caching instances in a plain
dict. The cache owns them forever;WeakValueDictionaryor explicit eviction bounds it. - Reading
gc.garbageas the leak list. It holds objects the collector refused; ordinary leaks never appear there.
Practice
The section mini-project covers this: lifetime reasoning behind the seeded cleanup defect, with a cycle-collection probe as the regression test.
Self-test
-
a = [];b = [a];a.append(b);del a, b. When is the memory freed?At the next cycle collection, not atdel. Refcounts stay positive through the cycle;gc.collect()reclaims both. -
sys.getrefcount(x)reads 2 for a fresh object at module level but 1 inside a function. Why?The argument adds a temporary reference, but 3.14 loads locals as borrowed references, so the function call adds none. Only deltas taken in the same context mean anything. -
weakref.ref([1, 2, 3])raisesTypeError. Why?listdoes not support weak references (a subclass oflistdoes). Hold weakref-able objects instead, or useWeakValueDictionaryfor caches. -
A slotted class cannot be weak-referenced. What is missing?
__weakref__in__slots__. Without that slot the type has no weak-reference support.
Completion criterion
Stop when
Your cycle probe frees on collect, your weakref callback fires, and you can state which reference keeps any object alive.
Mark passed, then open 4.1 Only mark this when you can do it without notes.Leads to
- 6.5 Profiling CPU and memory, and benchmarking honestly Memory growth in profiles often traces to cycles and caches.
- 3.4 Iterators, generators and lazy pipelines Lazy pipelines and weak caches both bound memory; compare the two tools.
Comes after
- 3.1 Names, identity, mutability, copying and hashabilityConnect aliasing to object lifetimes and weak references.
Resources for this unit
- Stas' Python Cookbook - selected path Run Part I on dictionaries, iteration, functions, closures, decorators, classes and context managers; Part II on modules, files, paths, environment and arguments; and Part IV on versions, dependencies, packaging and code quality. Finish by building one src-layout package from a blank directory.
- Python language reference Check Data model, Execution model, Import system and Exceptions whenever a claim depends on Python semantics. These pages are the authority when the course and a runtime observation disagree.
- gc - cycle garbage collector Read the cycle collector interface:
collect,get_count,garbageanddisable/enable. Use for the cycle-collection and measurement parts of refcounting-gc-weakrefs. - weakref - weak references Read weak-reference objects (
refcallbacks,proxyobjects) and theWeakValueDictionaryexample. Use for the weak-reference part of refcounting-gc-weakrefs.
Also in this section
- Packaging Python Projects Follow the packaging tutorial once from a blank directory, using a src layout, pyproject.toml, an isolated build and a clean-environment installation test.
- AlgoMaster Python - structured revision Use Functions, Modules and Packages, OOP, Advanced OOP, Exception Handling, Iterators and Generators, Type Hints and Annotations only after the cookbook pass. Open it for recall practice or a diagnosed weak mechanism, not as a second complete course.
- dataclasses - data classes Read the
@dataclassparameters (eq,order,frozen,slots),field()withdefault_factory, frozen instances, post-init processing,replace,asdictandastuple. Use for the validated frozen dataclass in attributes-protocols-dataclasses. - typing - type hints and protocols Read Protocols for structural typing and
runtime_checkablelimits, Generics forTypeVargenerics, andassert_typefor narrowing checks. Use for theProtocoland narrowing parts of type-hints-protocols; PEP 695 syntax itself is in the language reference.