795просмотров
33.2%от подписчиков
18 марта 2026 г.
question📷 ФотоScore: 875
Знаете ли вы, что объект в Python может не удалиться из памяти, даже если на него никто не ссылается? Создаете объект, он выходит из области видимости, сборщик мусора должен его подобрать – но тот висит в памяти. Виной циклическая ссылка: объект может ссылаться сам на себя или два объекта могут ссылаться друг на друга. gc умеет их собирать, но может это делать не всегда и не сразу. В долгоживущих процессах это превращается в утечку памяти. Посмотрим на момент утечки через tracemalloc: import tracemalloc tracemalloc.start()
snapshot1 = tracemalloc.take_snapshot() # Создаем объекты с циклическими ссылками
nodes = []
for _ in range(10000): a, b = {}, {} a["ref"] = b b["ref"] = a nodes.append(a) snapshot2 = tracemalloc.take_snapshot()
for stat in snapshot2.compare_to(snapshot1, 'lineno')[:3]: print(stat)
# Покажет в какой строке и сколько памяти выделено Python удаляет объекты через подсчет ссылок – как только счетчик доходит до нуля, объект удаляется. Но при циклической ссылке счетчик никогда не дойдет до нуля – a ссылается на b, b ссылается на a. Для таких случаев есть циклический сборщик gc, но если объекты создаются быстрее чем gc их собирает – память растет. Смотрим какие объекты накопились через objgraph: import objgraph
import gc gc.collect()
objgraph.show_most_common_types(limit=5)
# dict 25312
# list 3210
# ...
# Если dict растет между вызовами – утечка где-то в словарях objgraph.show_growth()
# Покажет какие типы объектов появились с прошлого вызова tracemalloc показывает где именно в коде выделяется память, objgraph показывает какие типы объектов накапливаются и кто на них ссылается – вместе они помогают найти утечку вплоть до конкретной строки. Код на салфетке x Кусочки кода