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 production environments.
1. Reproduce the Leak Locally
- Create a minimal reproducer – isolate the suspicious module or function.
-
Run under a memory monitor (e.g.,
psutil,top, or Docker stats) to confirm a steady rise in RSS. - Automate the load using a script that mimics production traffic.
import time, random
from myapp import process_item
while True:
data = [random.randint(0, 1000) for _ in range(10_000)]
process_item(data)
time.sleep(0.1)
2. Identify the Culprit
2.1 Use tracemalloc
import tracemalloc
tracemalloc.start()
# ... run workload ...
snapshot = tracemalloc.take_snapshot()
top_stats = snapshot.statistics('lineno')
for stat in top_stats[:10]:
print(stat)
2.2 Visualise with objgraph
pip install objgraph
import objgraph
objgraph.show_most_common_types(limit=10)
objgraph.show_growth(limit=5)
These tools reveal which objects keep accumulating.
3. Common Leak Patterns & Fixes
| Pattern | Symptoms | Fix |
|---|---|---|
| Global caches that never purge | Growing dict size | Use functools.lru_cache with maxsize or explicit eviction |
Reference cycles involving __del__
|
GC does not collect | Remove __del__, use weakref.finalize
|
| Unclosed file/network handles | File descriptors leak | Wrap resources in with statements |
| Large NumPy arrays retained by closures | Memory spikes after batch | Break closure references or copy‑on‑write |
Example: Breaking a reference cycle
import weakref
class Node:
def __init__(self, value):
self.value = value
self.parent = None
self.children = []
def set_parent(self, parent):
self.parent = weakref.ref(parent) # weak reference prevents a cycle
4. Production‑Ready Safeguards
- Enable GC debugging
import gc
gc.set_debug(gc.DEBUG_LEAK)
- Periodically force collection (e.g., every 10 minutes)
if time.time() - last_gc > 600:
gc.collect()
-
Monitor heap growth with Prometheus +
process_resident_memory_bytesmetric. - Deploy a watchdog container that restarts the service if RSS exceeds a threshold.
5. Automated Patch Toolkit
We've bundled the most effective fixes into a ready‑to‑run script. Download the pre‑configured script here, Get the complete patch tool, or Access the full repository fix to apply the recommendations with a single command.
Conclusion
Fixing memory leaks in production requires a systematic approach: reproduce, profile, isolate, and apply targeted fixes. By integrating the diagnostics above and using the provided automation script, you can keep your Python services performant and resilient.
Happy debugging!
Top comments (0)