Fundamentals 8 min read

Understanding Python Memory Management: Reference Counting, Circular References, and Generational Garbage Collection

Python abstracts memory management through reference counting, handles cyclic references with a generational garbage collector, and employs the weak generational hypothesis to efficiently reclaim objects, as illustrated by code examples demonstrating object creation, deletion, and the behavior of different GC generations.

Python Programming Learning Circle
Python Programming Learning Circle
Python Programming Learning Circle
Understanding Python Memory Management: Reference Counting, Circular References, and Generational Garbage Collection

If you have ever written C or C++, you know that memory management is critical and a small mistake can cause leaks.

When writing Python, however, we rarely think about memory handling—why is it so effortless?

Behind that convenience, Python silently manages memory for you; the following explains how.

1. Reference Counting

Python uses reference counting to manage memory.

When an object is created, a variable points to it, giving it a reference count of 1. Each additional variable that points to the object increments the count; removing a variable decrements it.

If an object’s reference count drops to 0, Python reclaims it.

Example code:

<code>class Person(object):
    def __init__(self, name):
        self.name = name

    def __del__(self):
        print('%s执行了del函数' % self.name)

while True:
    p1 = Person('p1')
    p2 = Person('p2')
    del p1
    del p2
    a = input('test:')
</code>

Running this shows that the `del` method of both objects is executed.

2. Circular References

Reference counting cannot resolve circular references.

For example, if object a references b and b references a, their counts never reach zero, so they are never reclaimed.

See the following example:

<code>class Person(object):
    def __init__(self, name):
        self.name = name

    def __del__(self):
        print('%s执行了del函数' % self.name)

while True:
    p1 = Person('p1')
    p2 = Person('p2')
    # 循环引用后,永远得不到释放
    p1.next = p2
    p2.prev = p1
    del p1
    del p2
    a = input('test:')
</code>

In this case the `del` functions are not called because the circular reference prevents the objects from being released.

3. Mark‑Sweep and Generational Collection

When a new object is created, Python places it on an internal “zero‑generation” list.

Consider creating four `Person` objects (p1‑p4) where p1 and p2 reference each other, and p3 and p4 have a reference count of 2:

<code>import sys

class Person(object):
    def __init__(self, name):
        self.name = name
        self.next = None
        self.prev = None

p1 = Person('p1')
p2 = Person('p2')
p3 = Person('p3')
p4 = Person('p4')

p1.next = p2
p2.prev = p1

temp1 = p3
temp2 = p4

print(sys.getrefcount(p1))
print(sys.getrefcount(p2))
print(sys.getrefcount(p3))
print(sys.getrefcount(p4))
</code>

The above code puts p1, p2, p3, and p4 onto the zero‑generation list (see diagram).

Because p1 and p2 reference each other, they form a circular reference; even after `del p1` and `del p2`, they remain unreleased.

Python therefore activates a new garbage‑collection mechanism. When the total number of allocated objects minus the number of reclaimed objects exceeds a threshold, the collector scans the zero‑generation list, reduces reference counts of objects involved in cycles, and frees those whose count drops to zero (e.g., p1 and p2).

Unreleased objects are then moved to a “first‑generation” list.

After the zero‑generation list has been processed a certain number of times, the collector traverses the first‑generation list and promotes surviving objects to a “second‑generation” list, applying the same principle.

4. Weak Generational Hypothesis

The core idea of generational GC is that the collector should handle new objects more frequently. An object that has just been created is “young”; an object that survives several collection cycles is “old”.

The hypothesis states that most young objects die quickly, while older objects tend to live longer.

Thus, most newly created objects become garbage soon after use, whereas occasional objects (e.g., web‑session data or configuration) persist for a long time.

By focusing on the zero‑generation list, Python’s collector spends most of its time reclaiming short‑lived objects and only occasionally processes older generations when thresholds are met.

- END -

Memory ManagementPythonGarbage CollectionReference CountingGenerational GC
Python Programming Learning Circle
Written by

Python Programming Learning Circle

A global community of Chinese Python developers offering technical articles, columns, original video tutorials, and problem sets. Topics include web full‑stack development, web scraping, data analysis, natural language processing, image processing, machine learning, automated testing, DevOps automation, and big data.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.