Что такое стек и куча в контексте памяти
Что проверяют
Понимаете ли вы, откуда берётся память под переменные и почему в Go этим почти не приходится управлять руками. Дальше обычно спрашивают про анализ побега, так что о нём стоит сказать самому.
Как отвечать
Стек это память вызова функции: аргументы, локальные переменные, адрес возврата. Кадр создаётся при входе в функцию и исчезает при выходе, поэтому выделение стоит почти ничего, а освобождение не требует участия сборщика мусора. Куча это общая область, где живут данные, срок жизни которых не совпадает с вызовом функции, и убирает их уже сборщик.
Специфика Go, ради которой вопрос и задают:
- у каждой горутины свой стек, он начинается с нескольких килобайт и растёт по мере надобности, поэтому горутин можно держать сотни тысяч;
- решение принимает компилятор, а не программист. Анализ побега смотрит, переживёт ли значение вызов функции: если да, оно уезжает в кучу. Посмотреть можно так:
go build -gcflags='-m' ./...; newи взятие адреса не означают кучу: указатель на локальную переменную, не покидающий функцию, спокойно живёт на стеке;- типичные причины побега: возврат указателя наружу, сохранение значения в интерфейс, передача в замыкание, которое живёт дольше, отправка в канал, слишком большой объект.
Практический смысл: чем меньше побегов, тем меньше работы сборщику. Отсюда предварительное выделение слайсов с нужной ёмкостью, переиспользование буферов, отказ от лишних преобразований в интерфейсы в горячем коде.
Где спотыкаются
Переносят правило из C++ и говорят «объекты всегда в куче, примитивы на стеке». В Go решает анализ побега.
Считают переполнение стека реальной угрозой для обычного кода: стек горутины растёт, и упереться можно в основном бесконечной рекурсией.
Не знают, чем измерить: профиль allocs в pprof и -benchmem в бенчмарках показывают аллокации на операцию.