Привет, Хабр! Сервис на FastAPI живёт четвёртые сутки, RSS вырос с 400 МБ до 3,2 ГБ, контейнер вот-вот получит OOMKilled. Внутри стоит tracemalloc, и он рисует ровную линию: питоновские объекты занимают те же 180 МБ, что и в первый час. gc.collect() из отладочного endpoint возвращает пару сотен собранных объектов и не меняет ничего.
Ситуация выглядит противоречиво ровно до тех пор, пока не вспомнишь, что RSS процесса и «память, занятая объектами Python» — величины из разных слоёв, и между ними стоят ещё два. Ниже разберём, как эти слои разделить, каким инструментом смотреть на каждый и что делать с результатом.
Три слоя между объектом и страницей памяти
Питоновский объект проходит длинный путь, прежде чем превратиться в страницу физической памяти.