Garbage Collection and Cyclic References
Overview
Python manages memory automatically using reference counting. Every object keeps a count of how many labels point to it, and when the count drops to zero, the object is immediately destroyed. Think of reference counting as returning a library book as soon as you finish reading it, and the garbage collector as the librarian sweeping the building at night for abandoned books. A cyclic reference occurs when objects point to each other (e.g., node `A` points to `B`, and `B` points to `A`). Reference counting cannot clean these up because their counts never reach zero even when no external variables point to them. To solve this, a background process called the garbage collector (using the `gc` module) periodically scans for unreachable cycles and destroys them. When testing memory management, you can use `sys.getrefcount()` to inspect an object's current reference count. Be aware of this common debugging trap: the count is always one higher than you expect because passing the object to the function creates a temporary reference. import sys my_list = [1, 2, 3] # Returns 2, not 1. The 'my_list' argument creates a temporary reference! print(sys.getrefcount(my_list))
It prevents memory leaks in long-running applications without requiring developers to manually allocate and free memory.
Where used: FastAPI background tasks, Celery workers, Data processing scripts
Why learn this
- You can avoid creating memory leaks in long-running servers.
- You understand why the `gc` module exists and when to use it.
Code walkthrough
import sys
x = []
print(sys.getrefcount(x))
y = x
print(sys.getrefcount(x))
del y
print(sys.getrefcount(x))
Focus: del y
Common mistakes
- Unintentional cycles caching: Storing large objects in global dictionaries or caches that reference each other, preventing memory from being freed until the program ends.
- Assuming del deletes objects: The `del` statement only deletes the variable name (the label), not the object. The object is only destroyed if that was the last label pointing to it.
Glossary
- reference counting
- A method of memory management where Python keeps track of how many times an object is being used. Example: `sys.getrefcount(obj)`
- memory leaks
- When a program fails to release memory that it no longer needs, eventually causing the system to run out of memory. Example: storing unused data in a global cache.
Recall questions
- What is the primary mechanism Python uses to know when to delete an object?
- Why is a secondary garbage collection process needed in addition to reference counting?
- Why does `sys.getrefcount(obj)` return a number that is one higher than the number of active variables pointing to it?
Understanding checks
What is the output of this code?
True
When `a` and `b` are deleted, their reference counts drop to `1` (because they point to each other). `gc.collect()` finds this unreachable cycle, cleans it up, and returns the number of collected objects, which is greater than `0`.
If you delete a variable using `del x`, does it immediately free the memory?
Not necessarily. It only decrements the reference count.
`del x` removes the label `x` and decrements the object's reference count by `1`. The object is only destroyed and its memory freed if that count reaches `0`.
Practice tasks
Break a cycle
The provided code creates a cyclic reference between a `parent` and `child` node. Modify the code to manually break the cycle before the end of the script so that reference counting alone can clean them up.
Challenge
Analyze Reference Counts
Create a list `a` and append it to itself. Then delete the label `a`. This creates a cyclic reference. Use the `gc` module to force a collection and print the number of collected objects.
Continue learning
Previous: Object identity: id() and memory references
Previous: Mutable vs immutable objects