← Назад к вопросам

Какие инструменты используешь для поиска утечек памяти?

1.3 Junior🔥 21 комментариев
#Python Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Инструменты для поиска утечек памяти в 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. Чек-лист для диагностики утечек

  1. Снять baseline профиль памяти:

    import tracemalloc
    tracemalloc.start()
    snapshot_baseline = tracemalloc.take_snapshot()
    
  2. Запустить операцию несколько раз:

    for _ in range(1000):
        do_operation()
    
  3. Сравнить со вторым снимком:

    snapshot_after = tracemalloc.take_snapshot()
    top_diff = snapshot_after.compare_to(snapshot_baseline, 'lineno')
    for stat in top_diff[:10]:
        print(stat)
    
  4. Использовать objgraph для поиска циклических ссылок:

    objgraph.show_most_common_types(limit=10)
    
  5. Профилировать с memory_profiler:

    @profile
    def suspicious_function():
        pass
    

Best Practices

  • Регулярно профилируй приложение — не ждись проблем
  • В production используй tracemalloc с периодическим логированием
  • Для веб-приложений добавь middleware для отслеживания памяти
  • Избегай циклических ссылок между объектами
  • Кэши должны иметь TTL и механизм очистки
  • Большие объекты освобождай явно (del, gc.collect())

Помни: утечка памяти на 10 млн пользователей — это 100 ГБ потраченной памяти!