🧠 Python Tutorial β€” Memory Management & Garbage Collection

Introduction 🌟

Python abstracts memory handling so developers don’t have to manage allocation manually. However, understanding how memory works internally is crucial for writing efficient, optimized programs.

Note

🧩 Python Memory Model β†’ Private Heap + Automatic Garbage Collection
πŸ—‘οΈ GC frees unused objects
πŸ“Œ Uses Reference Counting + Cyclic Garbage Collector

1. Python Memory Architecture 🧱

Python memory is divided into key components:

  • πŸ“ Object-specific Memory β€” where data objects live
  • πŸ“ Private Heap β€” managed entirely by Python
  • πŸ“ Memory Manager β€” handles allocation
  • πŸ“ Garbage Collector β€” frees unused memory

2. Reference Counting β€” Core Mechanism πŸ”’

In CPython (default Python implementation), every object keeps a reference count: the number of variables pointing to it.

ref_count.py

import sys

a = [1, 2, 3]
print(sys.getrefcount(a))

βœ” When reference count drops to 0 β†’ object is destroyed.

Example of Reference Counting

ref_count_example.py

a = [1, 2, 3]
b = a  # +1 reference
c = a  # +1 reference

del b  # -1
del c  # -1

# when all references removed β†’ GC cleans it

Note

πŸ’‘ Reference counting works instantly β€” no waiting needed.

3. Problem with Reference Counting β€” Cyclic References πŸ”

Reference counting cannot free cyclic references like this:

cyclic_ref.py

a = []
b = []
a.append(b)
b.append(a)  # both refer to each other

βœ” Their refcount never becomes 0 β†’ memory leak risk.

4. Cyclic Garbage Collector (GC) πŸ”„

Python runs a separate garbage collector to detect and free cycles.

gc_basic.py

import gc

print(gc.get_threshold())   # view GC settings
gc.collect()                # manually trigger garbage collection
  • Generation 0 β†’ short-lived objects
  • Generation 1 β†’ medium-lived
  • Generation 2 β†’ long-lived

βœ” GC runs automatically
βœ” Higher generations run less frequently

5. Python’s Generational Garbage Collection πŸ—οΈ

Objects are grouped into three generations:

GenerationMeaningCollection Frequency
0New objectsMost frequent
1Survived generation 0Less frequent
2Old objectsRarely collected

βœ” Objects that survive GC move to the next generation
βœ” Based on the principle that most objects die young

6. Memory Allocation in Python 🧩

Small Integer Caching

small_int_cache.py

a = 10
b = 10
print(a is b)  # True

βœ” Python reuses small integers (-5 to 256) for performance.

String Interning

string_interning.py

a = "hello"
b = "hello"
print(a is b)  # True

βœ” Common strings are shared to reduce memory usage.

7. Memory Leak Scenarios ⚠️

  • ❌ Unintentional global references
  • ❌ Cyclic references with custom classes
  • ❌ Holding unnecessary objects in lists/dicts
  • ❌ Cached objects not released

8. Avoiding Memory Leaks βœ”οΈ

  • βœ” Break cycles manually using del
  • βœ” Use weakref for weak references
  • βœ” Use context managers to release resources
  • βœ” Clear large lists/maps after use
  • βœ” Use generators instead of large lists

Using weak references

weakref_example.py

import weakref

class A:
    pass

a = A()
weak_ref = weakref.ref(a)

print(weak_ref())  # returns object
del a
print(weak_ref())  # returns None (object freed)

9. Monitoring Memory Usage πŸ“Š

Using sys.getsizeof()

sizeof_example.py

import sys
print(sys.getsizeof([1,2,3]))

Using tracemalloc

Tracks Python memory allocations.

tracemalloc_example.py

import tracemalloc

tracemalloc.start()

a = [i for i in range(10000)]
current, peak = tracemalloc.get_traced_memory()

print("Current:", current)
print("Peak:", peak)

tracemalloc.stop()

10. Real-World Example β€” Preventing Leaks in Class Cycles πŸ—οΈ

class_cycle_fix.py

import weakref

class Node:
    def __init__(self):
        self.parent = None
        self.children = []

root = Node()
child = Node()

child.parent = weakref.ref(root)   # weak link
root.children.append(child)

βœ” Breaks cycle β†’ avoids GC overhead

Memory Management Cheat Sheet πŸ“˜

ConceptDescription
Reference CountingMain mechanism; frees instantly when count is 0
Cyclic GCHandles cyclic references
Generations3 layers β†’ 0, 1, 2
Small Int CacheReuses -5 to 256
String InterningReuses common strings
weakrefUsed to avoid cycles
tracemallocMemory profiler

Best Practices πŸ’‘

  • βœ” Avoid creating large unnecessary objects
  • βœ” Use generators for huge data processing
  • βœ” Remove references using del
  • βœ” Use weakref for parent–child linked objects
  • βœ” Prefer context managers to manage resources
  • βœ” Don’t rely on GC β€” manage memory consciously

Conclusion πŸŽ‰

>>β€œPython handles memory automatically, but great developers understand how it works behind the scenes.” ✨

You now fully understand Memory Management & Garbage Collection in Python! Want the next topic? Try Object Identity, Name Binding, Data Classes, or Multithreading. Just tell me! 😊