Какие инструменты используешь для поиска утечек памяти?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Инструменты для поиска утечек памяти в Python
Утечки памяти — коварная проблема, которая проявляется не сразу. В production системах они приводят к деградации производительности и падениям приложения. Знание инструментов для диагностики — критический навык.
1. Встроенный модуль tracemalloc
Самый простой и встроенный способ профилирования памяти:
import tracemalloc
# Начать отслеживание
tracemalloc.start()
# Код приложения
data = [i for i in range(1000000)]
more_data = data * 10
# Снять снимок
current, peak = tracemalloc.get_traced_memory()
print(f"Текущая память: {current / 1024 / 1024:.2f} MB")
print(f"Пиковая память: {peak / 1024 / 1024:.2f} MB")
tracemalloc.stop()
Для детального анализа:
import tracemalloc
tracemalloc.start()
data = [i for i in range(1000000)]
# Получить топ функций по использованию памяти
snapshot = tracemalloc.take_snapshot()
top_stats = snapshot.statistics('lineno')
print("[ Top 10 потребителей памяти ]")
for stat in top_stats[:10]:
print(stat)
2. Модуль memory_profiler
Для точного профилирования по строкам кода:
pip install memory-profiler
from memory_profiler import profile
@profile
def allocate_memory():
a = [1] * 1000000 # 8 MB
b = [2] * 5000000 # 40 MB
return sum(a) + sum(b)
if __name__ == '__main__':
allocate_memory()
Запуск с анализом:
python -m memory_profiler script.py
Вывод показывает использование памяти на каждой строке:
Line # Mem usage Increment Occurrences Line Contents
=============================================================
1 38.6 MiB 0.0 MiB 1 @profile
2 38.6 MiB 0.0 MiB 1 def allocate_memory():
3 46.9 MiB 8.3 MiB 1 a = [1] * 1000000
4 86.9 MiB 40.0 MiB 1 b = [2] * 5000000
5 86.9 MiB 0.0 MiB 1 return sum(a) + sum(b)
3. Инструмент objgraph
Для анализа утечек через сильные ссылки:
pip install objgraph
import objgraph
# Показать самые распространённые типы объектов
objgraph.show_most_common_types(limit=10)
# Результат:
# function 5124
# wrapper_descriptor 2523
# method_descriptor 1734
# tuple 1203
# dict 987
Для отслеживания утечек между двумя точками:
import objgraph
def leak_memory():
# Снимок памяти в начале
objgraph.show_refs(
[[] for _ in range(100)],
filename='refs_before.png'
)
# Создание огромного числа объектов
big_list = [str(i) * 1000 for i in range(100000)]
# Снимок памяти в конце
objgraph.show_refs(
[s for s in big_list],
filename='refs_after.png'
)
leak_memory()
4. Модуль gc (garbage collector)
Для анализа циклических ссылок:
import gc
import sys
class Node:
def __init__(self, name):
self.name = name
self.ref = None
# Создать циклическую ссылку
a = Node('A')
b = Node('B')
a.ref = b
b.ref = a # Циклическая ссылка!
# Найти объекты в циклах
garbage = gc.garbage
print(f"Объектов в garbage: {len(garbage)}")
# Принудительно запустить garbage collection
gc.collect()
print(f"Собрано объектов: {gc.collect()}")
# Отследить ссылки
referrers = gc.get_referrers(a)
print(f"На объект a ссылаются {len(referrers)} объекты")
for ref in referrers:
print(f" - {type(ref)}")
5. Профайлер py-spy
Для профилирования работающего приложения в реальном времени:
pip install py-spy
python -m py_spy record -o profile.svg -- python app.py
Генерирует flamegraph, показывающий использование памяти.
6. Инструмент Pympler
Мощный инструмент для анализа памяти:
pip install pympler
from pympler import tracker
import tracemalloc
# Создать tracker
tr = tracker.SummaryTracker()
def allocate_stuff():
data = [i for i in range(1000000)]
strings = [str(i) * 100 for i in range(100000)]
return data, strings
allocate_stuff()
# Показать топ потребителей
tr.print_diff()
7. Встроенная диагностика Flask/Django
Для веб-приложений:
# Flask с flask-debugtoolbar
from flask_debugtoolbar import DebugToolbarExtension
from flask import Flask
app = Flask(__name__)
app.config['DEBUG'] = True
toolbar = DebugToolbarExtension(app)
# Показывает использование памяти, SQL запросы и т.д.
Для Django:
pip install django-debug-toolbar
8. Практический пример: поиск утечки
Сценарий: приложение накапливает кэш, который растёт бесконечно:
import tracemalloc
import sys
class CacheMemoryLeak:
def __init__(self):
self.cache = {} # Опасный кэш без очистки!
def add_to_cache(self, key, value):
self.cache[key] = value * 1000 # Большой объект
def get_from_cache(self, key):
return self.cache.get(key)
def detect_leak():
tracemalloc.start()
cache_obj = CacheMemoryLeak()
print("Снимок 1:")
# Добавить данные
for i in range(100000):
cache_obj.add_to_cache(f"key_{i}", i)
snapshot1 = tracemalloc.take_snapshot()
top_stats = snapshot1.statistics('lineno')
print(top_stats[0])
print("\nСнимок 2:")
# Ещё больше данных
for i in range(100000, 200000):
cache_obj.add_to_cache(f"key_{i}", i)
snapshot2 = tracemalloc.take_snapshot()
top_stats = snapshot2.statistics('lineno')
print(top_stats[0])
# Отследить разницу
top_diff = snapshot2.compare_to(snapshot1, 'lineno')
print("\nТоп различий:")
for stat in top_diff[:3]:
print(stat)
detect_leak()
9. Чек-лист для диагностики утечек
-
Снять baseline профиль памяти:
import tracemalloc tracemalloc.start() snapshot_baseline = tracemalloc.take_snapshot() -
Запустить операцию несколько раз:
for _ in range(1000): do_operation() -
Сравнить со вторым снимком:
snapshot_after = tracemalloc.take_snapshot() top_diff = snapshot_after.compare_to(snapshot_baseline, 'lineno') for stat in top_diff[:10]: print(stat) -
Использовать objgraph для поиска циклических ссылок:
objgraph.show_most_common_types(limit=10) -
Профилировать с memory_profiler:
@profile def suspicious_function(): pass
Best Practices
- Регулярно профилируй приложение — не ждись проблем
- В production используй tracemalloc с периодическим логированием
- Для веб-приложений добавь middleware для отслеживания памяти
- Избегай циклических ссылок между объектами
- Кэши должны иметь TTL и механизм очистки
- Большие объекты освобождай явно (del, gc.collect())
Помни: утечка памяти на 10 млн пользователей — это 100 ГБ потраченной памяти!