В профиле tracemalloc текущее потребление вернулось почти к исходному, но пиковое осталось высоким: что это означает?
Это означает, что после запуска профилирования программа создала временный объём Python-объектов, который затем освободила: current уменьшился, а peak сохранил максимальное зафиксированное значение. Такой профиль указывает прежде всего на высокий временный пик, а не на продолжающуюся утечку.
tracemalloc появился в стандартной библиотеке Python для отслеживания распределений памяти, выполняемых Python-кодом, и поиска мест, где создаются объекты. До этого по одному RSS процесса было трудно связать рост памяти с конкретными строками исходного кода.
Инструмент решает задачу анализа Python-распределений, но не является полным профилировщиком всей памяти процесса. Поэтому его показатели нужно интерпретировать отдельно от RSS и данных о памяти, выделенной нативными расширениями.
Высокий пик может возникать при сортировке, сериализации, построении промежуточных коллекций или пакетной обработке. Если смотреть только на текущее значение, кратковременная нагрузка останется незамеченной и может приводить к аварийному завершению процесса при ограниченном объёме памяти.
Если же принять высокий пик за утечку, можно ошибочно искать потерянные ссылки, хотя объекты уже освобождены. В результате оптимизация будет направлена не на устранение удержания памяти, а на уменьшение разового объёма промежуточных данных.
current — объём памяти, отслеживаемой tracemalloc в данный момент. peak — максимальное значение такого объёма с момента запуска трассировки или последнего сброса пика.
После освобождения временных объектов current может приблизиться к исходному уровню, но peak не уменьшается автоматически. reset_peak() устанавливает точку отсчёта для нового измерения; он не освобождает память и не меняет жизненный цикл объектов.
Для поиска причины пика следует анализировать снимки или статистику распределений во время подозрительного этапа, а не только итоговые значения. Важно также учитывать, что tracemalloc отслеживает не все виды памяти: например, память, выделенную некоторыми нативными библиотеками вне отслеживаемых Python-распределений, он может не показать.
Высокий peak означает риск пикового потребления, но сам по себе не доказывает утечку. Для признака утечки нужно наблюдать, растёт ли current после повторяющихся одинаковых операций и остаются ли объекты достижимыми.
Сервис формировал отчёт из большого набора записей. После завершения формирования current возвращался почти к исходному значению, однако peak резко возрастал, а контейнер иногда получал нехватку памяти.
Рассматривались три варианта. Увеличение лимита памяти быстро устраняло сбой, но только маскировало проблему. Поиск утечки был полезен для проверки гипотезы, но не объяснял отсутствие роста current. Потоковая генерация отчёта уменьшала объём одновременно существующих промежуточных объектов, но усложняла обработку ошибок и повторное использование данных.
Выбрали потоковую обработку с ограниченным размером пакета. После этого итоговое текущее потребление почти не изменилось, зато пиковое значение снизилось, поскольку крупная промежуточная коллекция больше не создавалась целиком. Это подтвердило, что исходная проблема была временным пиком, а не удержанием объектов.
current доказательством отсутствия утечки?Нет. Низкий current показывает только состояние на момент измерения. Утечка может проявляться постепенно: после каждой итерации остаётся небольшой объём объектов, и на коротком интервале это незаметно. Надёжнее сравнивать current после одинаковых этапов нескольких повторений и анализировать статистику снимков.
peak может не совпадать с пиком RSS процесса?peak относится к памяти, которую отслеживает tracemalloc, а RSS включает более широкий набор областей: память интерпретатора, нативных библиотек, отображённых файлов, служебные структуры и страницы, удерживаемые аллокатором процесса. Поэтому RSS может быть выше peak, а изменение RSS может не отражаться пропорционально в данных tracemalloc.
Распределения, произошедшие до tracemalloc.start(), не будут полноценно представлены в последующих измерениях как новые трассируемые выделения. Из-за этого стартовый current и зафиксированный peak могут не отражать фактическую историю потребления процесса. Для сравнимых экспериментов трассировку запускают до исследуемой операции и одинаково прогревают сценарий.