Что происходит в программе при выделении памяти
Что проверяют
Знаете ли вы, кто в Go решает, где окажется значение, на стеке или в куче, и во что обходится выделение в куче. Следом обычно просят показать, как найти лишние аллокации в горячем коде.
Как отвечать
Решение принимает компилятор, а не new или make. Escape-анализ смотрит, может ли значение пережить функцию: если ссылка на него уходит наружу (возврат указателя, запись в глобальную переменную, замыкание, которое живёт дольше), значение отправляется в кучу. Иначе оно остаётся на стеке горутины, даже если создано через new. Решения компилятора видны через go build -gcflags=-m.
Стек горутины стартует с нескольких килобайт и растёт копированием: runtime выделяет стек вдвое больше и переносит содержимое. Выделение на стеке почти бесплатно и не нагружает сборщик мусора.
Куча устроена по мотивам TCMalloc:
- классы размеров: мелкие объекты до 32 КБ округляются до одного из фиксированных размеров и берутся из спанов своего класса;
mcache: локальный кэш у каждого P (логического процессора), поэтому большинство выделений проходит без блокировок;mcentralиmheap: когда локальный кэш пуст, спан берут из общего пула, а тот при нехватке просит память у ОС черезmmap;- крупные объекты: больше 32 КБ выделяются сразу из
mheap.
Освобождает память конкурентный сборщик: трёхцветная пометка с барьером записи, без поколений и без перемещения объектов. Частоту задаёт GOGC (по умолчанию 100, то есть сборка при росте кучи вдвое от живых данных), а GOMEMLIMIT задаёт мягкий лимит памяти, что важно в контейнере. Аллокации ищут через pprof с профилем allocs и через b.ReportAllocs() в бенчмарках.
Где спотыкаются
Говорят, что new и make выделяют память в куче. Это не так, место определяет escape-анализ.
Передают всё по указателю «для скорости». Указатель часто вынуждает значение уйти в кучу, и маленькая структура, переданная по значению, оказывается дешевле.
Считают сборку мусора бесплатной, раз она фоновая. Короткие паузы с остановкой мира всё же есть, а горутины, которые активно выделяют память, привлекаются к пометке (mark assist) и замедляются.