Back to articles

Python Memory Optimization & Cyclic Garbage Collection

August 5, 20266 min read
Python
Performance
Memory
Internals

Memory optimization in high-throughput Python applications requires a clear understanding of CPython’s internal memory manager (PyMalloc) and cyclic garbage collector (gc module).

Reference Counting & PyObject

Every Python object has a ob_refcnt header. When references are created or destroyed, ob_refcnt increments or decrements immediately.

import sys

class Node:
    def __init__(self, value: int):
        self.value = value
        self.neighbor = None

a = Node(100)
print("Initial ref count:", sys.getrefcount(a) - 1)  # -1 for sys.getrefcount temporary ref

b = a
print("After assignment ref count:", sys.getrefcount(a) - 1)

Reference Cycles & Cyclic GC

Reference counting fails when objects reference each other in a closed cycle:

import gc

def create_cycle():
    node1 = Node(1)
    node2 = Node(2)
    # Creating a cyclic reference
    node1.neighbor = node2
    node2.neighbor = node1

# Disable automatic GC for demonstration
gc.disable()
create_cycle()

print("Unreachable objects detected:", gc.collect())

Optimizing Memory with __slots__

By default, Python instances use a dynamic __dict__ dictionary to store attributes. For millions of objects, this creates huge memory overhead.

import sys

class StandardPoint:
    def __init__(self, x: float, y: float, z: float):
        self.x = x
        self.y = y
        self.z = z

class SlottedPoint:
    __slots__ = ('x', 'y', 'z')
    def __init__(self, x: float, y: float, z: float):
        self.x = x
        self.y = y
        self.z = z

std_p = StandardPoint(1.0, 2.0, 3.0)
slot_p = SlottedPoint(1.0, 2.0, 3.0)

print("Standard instance size + dict:", sys.getsizeof(std_p) + sys.getsizeof(std_p.__dict__))
print("Slotted instance size:", sys.getsizeof(slot_p))

Production Guidelines

  1. Use __slots__ for lightweight data structures created in high volume.
  2. Break circular references explicitly or use weakref.ref for back-pointers.
  3. Monitor heap allocations using tracemalloc in staging and load testing.