The essentials

Quick reference

One focused task per row. Jump to the related section for complete, working examples.

UseSyntaxExamples
Measure shallow sizeshallow_bytes = sys.getsizeof(value)View examples
Inspect CPython referencescount_with_temporary = sys.getrefcount(value)View examples
Run cyclic collectionunreachable = gc.collect()View examples
Check collector statecollector_enabled = gc.isenabled()View examples
Read GC thresholdsthresholds = gc.get_threshold()View examples
Freeze tracked objectsgc.freeze()View examples
Create a weak referencereference = weakref.ref(instance)View examples
Cache values weaklycache = weakref.WeakValueDictionary()View examples
Associate metadata weaklymetadata = weakref.WeakKeyDictionary()View examples
Track instances weaklyinstances = weakref.WeakSet()View examples
Register a finalizercleanup = weakref.finalize(owner, close_resource, resource_id)View examples
Start allocation tracingtracemalloc.start(10)View examples
Capture a snapshotsnapshot = tracemalloc.take_snapshot()View examples
Compare snapshotschanges = after.compare_to(before, 'lineno')View examples
Read traced current and peakcurrent, peak = tracemalloc.get_traced_memory()View examples

Python memory work starts with ownership: determine which objects remain reachable and why before forcing collection or tuning thresholds. CPython primarily uses reference counting plus a cyclic collector, while other implementations may differ. Use weak references for non-owning relationships and tracemalloc for Python allocation evidence, then corroborate with process and native-memory tools when needed.

Step by step

Detailed examples

01

Distinguish shallow, traced, and process memory

sys.getsizeof is shallow and may invoke an object's __sizeof__; summing it recursively risks double-counting shared objects. tracemalloc observes allocations routed through traced Python allocators, not every native library allocation. RSS includes additional allocator arenas, stacks, mappings, and native memory, and may remain high after objects are freed. sys.getrefcount is CPython-specific and perturbs the value it observes.

Show why shallow size is not graph size
import sys

shared = 'ready'
values = [shared, shared, shared]
print(sys.getsizeof(values) > 0)
print(sum(item is shared for item in values))
print(sys.getsizeof(shared) <= sys.getsizeof(shared + '!'))
Output
True
3
True
Back to quick reference ↑
02

Understand reachability and cyclic collection

A reachable object is live even if the program no longer needs it. CPython reference counting usually releases acyclic objects promptly; the gc module detects unreachable reference cycles. gc.collect is a diagnostic or lifecycle tool, not a general leak fix. Python 3.14 removed generation 1 and changed threshold behavior, and the free-threaded build adds process-memory heuristics, so do not hard-code old generational assumptions.

Collect an unreachable cycle
import gc
import weakref

class Node:
    pass

node = Node()
node.self = node
reference = weakref.ref(node)
del node
gc.collect()
print(reference() is None)
print(gc.isenabled())
Output
True
True
Back to quick reference ↑
03

Model observation without ownership

weakref.ref returns the referent while it is alive and None afterward. Keep the dereference and None check together to avoid a race in threaded code. Not every type supports weak references; subclasses and classes using __slots__ need appropriate support, commonly a __weakref__ slot. A weak proxy is convenient but can raise ReferenceError between accesses.

Observe an object's lifetime
import weakref

class Session:
    pass

session = Session()
reference = weakref.ref(session)
print(reference() is session)
del session
print(reference() is None)
Output
True
True
Back to quick reference ↑
04

Build caches and registries that do not retain owners

WeakValueDictionary suits canonical-object caches, WeakKeyDictionary attaches side data to owners, and WeakSet tracks live instances. Entries may disappear at any time once no strong reference remains, so these containers are unsuitable when stable membership is required. Iteration also needs care because concurrent lifetime changes can remove entries.

Let a weak cache evict an unowned value
import gc
import weakref

class Record:
    pass

cache = weakref.WeakValueDictionary()
record = Record()
cache['current'] = record
print('current' in cache)
del record
gc.collect()
print('current' in cache)
Output
True
False
Back to quick reference ↑
05

Separate cleanup from object destruction

weakref.finalize keeps the callback alive until it runs, invokes it at most once, and can be called explicitly for deterministic cleanup. The callback must not capture the owner, directly or indirectly, or the owner may never become unreachable. Prefer context managers for scarce resources because garbage collection timing is not a reliable resource-management schedule.

Invoke an idempotent finalizer explicitly
import weakref

class Owner:
    pass

events = []
owner = Owner()
cleanup = weakref.finalize(owner, events.append, 'closed')
print(cleanup.alive)
cleanup()
cleanup()
print(events)
print(cleanup.alive)
Output
True
['closed']
False
Back to quick reference ↑
06

Compare allocation snapshots around one operation

Start tracing early enough to cover suspect allocations, take a baseline, run a controlled workload, and compare snapshots by traceback, filename, or line. Filter known noise and retain the workload so growth remains observable. Snapshot totals are evidence of allocation sites, not proof of a leak; verify continued growth and the references retaining objects. Frame depth improves attribution at a runtime and memory cost.

Trace a controlled allocation
import tracemalloc

tracemalloc.start(5)
before = tracemalloc.take_snapshot()
values = [bytes(64) for _ in range(100)]
after = tracemalloc.take_snapshot()
changes = after.compare_to(before, 'lineno')
current, peak = tracemalloc.get_traced_memory()
print(tracemalloc.is_tracing())
print(bool(changes))
print(peak >= current >= 0)
tracemalloc.stop()
print(tracemalloc.is_tracing())
Output
True
True
True
False
Back to quick reference ↑

Local code tester

Watch a weak registry shrink

Track two objects without owning them, remove one strong reference, and force cyclic collection for a deterministic demonstration.

Runs in your browser
Output
Press Run to load Python locally.

Sources and further reading

References

Authoritative documentation used to verify and expand this cheat sheet.

  1. Python Software Foundationgc — Garbage Collector interfacedocs.python.org
  2. Python Software Foundationweakref — Weak referencesdocs.python.org
  3. Python Software Foundationtracemalloc — Trace memory allocationsdocs.python.org
  4. Python Software Foundationsys — System-specific parameters and functionsdocs.python.org

Help us improve

Found a typo or missing example?

Tell us what would make this cheat sheet clearer, more complete, or more useful.

Share feedback