Fixing Python Memory Leaks in Production
Introduction
Memory leaks in long‑running Python services can silently degrade performance, increase latency, and eventually cause crashes. This guide walks you through diagnosing, fixing, and preventing memory leaks in a production environment.
Common Culprits
- Unclosed resources (files, sockets, DB connections)
-
Reference cycles involving objects with
__del__methods - Large caches that never evict stale data
- Third‑party extensions written in C that don’t free memory correctly
Step‑by‑Step Diagnosis
- Enable runtime monitoring
import psutil, os, time
def print_mem(label):
proc = psutil.Process(os.getpid())
mem = proc.memory_info().rss / (1024 ** 2)
print(f"[{label}] RSS: {mem:.2f} MiB")
-
Capture allocation snapshots with
tracemalloc
import tracemalloc
tracemalloc.start()
# ... run the code path you suspect ...
snapshot = tracemalloc.take_snapshot()
top = snapshot.statistics('lineno')
for stat in top[:10]:
print(stat)
The output points you to the exact lines allocating the most memory.
-
Visualize object graphs with
objgraph
import objgraph
objgraph.show_most_common_types(limit=5)
objgraph.show_backrefs([leaking_obj], filename='leak.png')
- Force a collection and compare
import gc
gc.collect()
print_mem('after gc')
Practical Fixes
Use Context Managers
# Bad – file never closed
f = open('log.txt')
for line in f:
process(line)
# Good – automatically closed
with open('log.txt') as f:
for line in f:
process(line)
Break Reference Cycles
import weakref
class Node:
def __init__(self, name):
self.name = name
self.parent = None
self.children = []
def add_child(self, child):
child.parent = weakref.ref(self) # weak reference prevents a cycle
self.children.append(child)
Limit Cache Size
from functools import lru_cache
@lru_cache(maxsize=256) # prevents unbounded growth
def heavy_computation(x):
...
Explicitly Release C Extensions
import numpy as np
arr = np.arange(1_000_000)
# When done with a large array from a C extension
del arr
import gc; gc.collect()
Production Guardrails
-
Prometheus metrics: expose
process_resident_memory_bytes. - Alerting: trigger when RSS grows > 20 % over a 5‑minute window.
- Rolling restarts: schedule periodic restarts for services that cannot be fully leak‑free.
Automated Patch Tool
If you need a ready‑made script to scan and patch common leak patterns, Download the pre‑configured script here. For a full‑featured utility that integrates with CI pipelines, Get the complete patch tool. You can also Access the full repository fix for deeper customisation.
By systematically monitoring, isolating, and correcting the root causes outlined above, you can keep your Python services memory‑efficient and reliable in production.
Top comments (0)