Introduction
Memory leaks in Python can silently degrade performance, especially in long‑running production services. This guide walks you through diagnosing, fixing, and preventing leaks with real‑world examples.
Why Python Still Leaks
- Reference cycles involving objects with
__del__. - Unreleased C extensions.
- Global caches and mutable default arguments.
Quick Checklist
- Enable
tracemalloc. - Run
objgraphto spot unexpected object graphs. - Profile with
memory_profiler. - Review third‑party libraries.
Step‑by‑Step Troubleshooting
Reproduce the Leak Locally
# leak_demo.py
cache = []
def add():
# each call adds a 1 MiB string
cache.append('x' * 1024 * 1024)
if __name__ == '__main__':
while True:
add()
Run the script and watch RSS grow.
Capture a Snapshot with tracemalloc
import tracemalloc, time
tracemalloc.start()
# ... run your workload ...
time.sleep(5) # let the workload settle
snapshot = tracemalloc.take_snapshot()
top_stats = snapshot.statistics('lineno')
print("[ Top 10 memory consumers ]")
for stat in top_stats[:10]:
print(stat)
The output points to the file and line responsible.
Visualise Object Graphs
pip install objgraph
import objgraph, gc
gc.collect()
objgraph.show_most_common_types(limit=5)
objgraph.show_backrefs(objgraph.by_type('list')[0], max_depth=3)
If you see a growing list of a custom class, you likely have a cache that never clears.
Fix Common Patterns
Mutable default arguments
# Bad
def append_item(item, container=[]):
container.append(item)
return container
# Fixed
def append_item(item, container=None):
if container is None:
container = []
container.append(item)
return container
Unclosed file handles
# Bad
def read_data(path):
f = open(path)
return f.read() # file never closed
# Fixed
def read_data(path):
with open(path) as f:
return f.read()
C extension leaks
Upgrade the extension or wrap the call in a subprocess to isolate the leak.
Production‑Ready Monitoring
-
Prometheus exporter for
process_resident_memory_bytes. - Grafana alerts when RSS grows > 20 % over a 10‑minute window.
-
Automatic heap dumps via
gdbwhen thresholds are breached.
Automated Patch Tool
We’ve packaged a reusable script that scans for the three patterns above and rewrites the offending files. Download the pre‑configured script here. For a full CI integration, you can also Get the complete patch tool and embed it in your pipeline. Need the source? Access the full repository fix.
Wrap‑Up
Fixing memory leaks is iterative: detect, isolate, patch, and monitor. By combining tracemalloc, objgraph, and disciplined code reviews, you can keep your Python services healthy in production.
Top comments (0)