TGViewer
About Python [ru] About Python [ru] @python_tesst · 6.44K subscribers
Post #2786 355
⁣Профилирование утечек памяти в asyncio: трассировка task-стека и gc.get_objects

Утечки памяти в asyncio-приложениях — та ещё головная боль. Стандартные pympler или objgraph часто показывают не то, потому что объекты висят в стеках корутин или в циклических ссылках внутри Task-ов. Есть два рабочих подхода, которые я сам использую.

Трассировка стека через Task.get_stack()

Когда таск зависает в бесконечном ожидании (например, из-за Future, который никогда не завершится), его кадры стека держат ссылки на большие объекты. Берёшь asyncio.all_tasks(), для каждого вызываешь get_stack(), ищешь кадры с подозрительными локальными переменными. Прямо видишь, что висит и сколько весит:

async def leaky_task():
data = [0] * 10_000_000
await asyncio.Future()

tasks = asyncio.all_tasks()
for t in tasks:
stack = t.get_stack()
if stack and 'data' in stack[0].f_locals:
obj = stack[0].f_locals['data']
print(f'Task {t} держит {type(obj)} размером {sys.getsizeof(obj)} байт')


Поиск забытых ссылок через gc.get_objects

Снимаешь снапшот до операции, потом после, ищешь разницу. Только не забудь вызвать gc.collect() перед каждым снимком, иначе поймаешь кучу короткоживущих объектов.

def find_growth(snapshot_before):
new_objects = []
for obj in gc.get_objects():
if id(obj) not in snapshot_before and hasattr(obj, '__class__'):
new_objects.append(obj.__class__.__name__)
return Counter(new_objects).most_common(5)


Почему это работает? В asyncio event loop держит ссылки на все незавершённые таски. Если корутина содержит локальные переменные или замыкания — они не утилизируются, пока таск не завершится. gc.get_objects находит объекты, которые держатся циклическими ссылками в колбэках или корутинах.

Практические советы:
- Включи gc.set_debug(gc.DEBUG_SAVEALL) — он сохраняет недостижимые объекты, можно посмотреть, кто не собирается.
- Для единичных подозрительных корутин sys.getrefcount до и после — быстро, но грубо.
- Для продакшена есть tracemalloc, который не требует остановки приложения.

Типичная ошибка: Не вызывать gc.collect() перед снимком — тогда разница будет забита короткоживущими объектами из недавних операций, что маскирует реальную утечку.

Вывод: Трассировка стека тасков ловит утечки внутри активных корутин, а gc.get_objects — глобальные забытые объекты и циклические ссылки, и без них вы будете сидеть с логами и гадать, где память утекает.
More from @python_tesst
  1. Sep 29, 2026Claude Sonnet 5.5 — уже не слив, релиз официально состоялся Прайс не трогали: $2 за миллио…
  2. Sep 29, 2026Post #3194
  3. Sep 29, 2026Дженсен Хуанг выкатил NVIDIA Open Agent Safety Platform — и притащил с собой 100+ партнеро…
  4. Sep 29, 2026Стикмену теперь под силу снести любой сайт. Чувак под это навайбкодил целую игруху: грузиш…
  5. Sep 27, 2026OpenAI метит в подписку за 500 баксов Что там в описании тарифа? Пока что от ChatGPT Pro о…
  6. Sep 27, 2026Свежая обложка The Economist подъехала Журналисты: да мы вообще не сгущаем краски Те же жу…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →