Что такое живая зона памяти в Go?
Что проверяют
В документации Go термина «живая зона памяти» нет, и это часть проверки. Спрашивают про живое множество, то есть про объекты, достижимые от корней, и хотят увидеть, что вы понимаете сборку по достижимости и связь объёма живых данных с частотой сборок.
Как отвечать
Живой считается память, достижимая от корней: стеки горутин, глобальные переменные, регистры. Сборщик в Go это конкурентный трёхцветный mark and sweep, не перемещающий и не поколенческий. Он помечает достижимое, остальное возвращает в аллокатор, адреса объектов при этом не меняются.
Объём живых данных после пометки задаёт цель следующего цикла. Переменная GOGC определяет, насколько куча может вырасти относительно живого множества до запуска новой сборки, по умолчанию она равна 100, то есть куча растёт примерно вдвое. GOMEMLIMIT задаёт мягкий потолок для всей памяти рантайма и нужен в контейнере с лимитом. Практический вывод: чем больше живых данных, тем выше порог и абсолютное потребление, а если давит частота сборок, выбор между уменьшением живого множества и повышением GOGC при запасе по памяти.
Попадёт ли значение в кучу, решает escape analysis, а не вызов make или new: то, что не покидает функцию, живёт на стеке и сборщика не касается. Смотрят это флагом компилятора для вывода решений об escape.
Где спотыкаются
Присваивают nil локальной переменной в конце функции, чтобы «помочь сборщику». Компилятор и так знает, что после последнего использования переменная мертва. Осмысленно обнулять только долгоживущие ссылки: элемент среза при удалении, поле объекта, который возвращается в пул.
Считают сборщик Go поколенческим и перемещающим и предлагают «сжать кучу». Компактизации в Go нет, поэтому фрагментация лечится формой данных, а не настройками сборщика.
Путают живое множество и потребление памяти процессом. Освобождённые страницы возвращаются операционной системе не сразу, поэтому вывод об утечке только по метрике процесса ошибочен: сравнивать нужно живую кучу и то, что рантайм уже отдал обратно.