Имя и объект имеют разный жизненный цикл
Переменная связывает имя с объектом; несколько имён или контейнеров могут ссылаться на один объект. Удаление одного имени не уничтожает остальные ссылки. Если большой список по-прежнему хранится в кэше или другой коллекции, он остаётся доступным программе. Поэтому операция del сама по себе не является командой освободить всю связанную память немедленно. В CPython подсчёт ссылок дополняется механизмом сборки циклического мусора. Но точные детали управления памятью относятся к реализации и версии. Не стоит строить переносимую логику программы на предположении о мгновенном уничтожении любого объекта. Для файлов, соединений и других внешних ресурсов используют явный корректный жизненный цикл, а не надежду на случайный момент сборки.
Размер объекта не равен памяти процесса
Функция sys.getsizeof сообщает размер самого объекта в смысле реализации, но не складывает автоматически размеры всего дерева объектов, на которые он ссылается. Небольшой контейнер может удерживать крупные элементы. Если два контейнера ссылаются на один объект, наивное суммирование способно посчитать его дважды. Показатель памяти процесса, текущие отслеживаемые выделения и пик потребления отвечают на разные вопросы. Освобождение объектов не обязательно сразу уменьшает наблюдаемую операционной системой память процесса: распределитель может сохранять выделенные области для повторного использования. Поэтому одно число из системного монитора не позволяет уверенно определить источник проблемы или доказать, что исправление не сработало.
Сравнивайте одинаковые этапы сценария
Модуль tracemalloc помогает отслеживать выделения памяти Python и сравнивать снимки по местам их возникновения. Его нужно включать до интересующего участка, иначе ранние выделения не попадут в историю. При этом не вся память нативных библиотек обязательно отражается таким измерением, поэтому границы инструмента важно учитывать. Для диагностики задайте небольшой повторяемый сценарий: одинаковый вход, одинаковое число операций и контрольные точки после завершения работы. Отделите прогрев кэша от устойчивого роста. Затем ищите, какие структуры увеличиваются и почему остаются достижимыми. Изменяйте одну причину за раз и повторяйте измерение. Принудительный вызов сборщика без анализа ссылок не заменяет поиск источника удержания.
Попробуйте на практике
Постройте бумажную модель ссылок, чтобы проверить понимание памяти без запуска больших вычислений.
- Нарисуйте один объект список и две стрелки к нему от имён A и B. Укажите, что список содержит ссылки на три других объекта.
- Удалите стрелку A и объясните, почему список остаётся доступным через B. Затем добавьте ссылку из условного кэша.
- Нарисуйте два контейнера, указывающих на один общий объект. Покажите, где простое сложение размеров может посчитать его повторно.
- Составьте план измерения реальной программы: момент включения tracemalloc, две контрольные точки, одинаковый вход и показатель, который хотите сравнить.
Как проверить результат. Схема различает имя, контейнер и общий объект. План измерения указывает, что именно отслеживается, и не приравнивает размер одного объекта к общему потреблению процесса.
Частые вопросы
Нужно ли регулярно вызывать сборщик вручную?
Не как универсальное средство оптимизации. Сначала выясните, что удерживает объекты и какой показатель растёт. Ручное вмешательство без измерений может добавлять затраты и не решать проблему.
Генератор всегда экономит память?
Он может избежать создания полной промежуточной коллекции, но итог зависит от того, как потребитель использует значения и какие ссылки сохраняются. Нужна проверка конкретного сценария.
Самостоятельный разбор темы. Содержание конкретной обучающей программы здесь не представлено.