Куда уходит память?
Многие любят Go за встроенный сборщик мусора (GC) и простоту работы с указателями. Но чтобы писать по-настоящему быстрый код, нужно понимать, где именно аллоцируется память: на стеке (stack) или в куче (heap).
Выделение памяти на стеке обходится практически бесплатно (это просто сдвиг указателя), а вот аллокации в куче нагружают GC и снижают общую производительность приложения.
Как компилятор Go решает, куда положить переменную? С помощью Escape-анализа.
Главное правило: если ссылка на переменную «убегает» (escapes) за пределы функции, где она была создана, переменная отправляется в кучу. Если нет - остается на быстром стеке.
Когда переменная почти наверняка «убегает» в кучу:
• Возврат указателя из функции (например, return &MyStruct{}).
• Отправка указателя или структуры с указателями в канал (компилятор не знает, когда и в какой горутине получатель это прочитает).
• Присвоение значения в interface{}. Классический пример: вызов fmt.Println(myVar) отправляет myVar в кучу, так как функция под капотом принимает ...any.
• Размер переменной слишком велик для стека или неизвестен на этапе компиляции (например, слайс динамического размера, который мы инициализируем через переменные).
Как проверить свой код?
Запустите сборку с флагом -gcflags="-m":
go build -gcflags="-m" main.go
В консоли вы увидите строки вида escapes to heap - компилятор прямо расскажет, какие переменные переехали в кучу и почему.
💡 Практический совет:
Не используйте указатели слепо в надежде «избежать лишнего копирования». Очень часто передача небольшой структуры по значению (создание копии на быстром стеке) обходится гораздо дешевле, чем передача по указателю (аллокация в куче + последующая работа сборщика мусора).
#golang #memory #backend #оптимизация
👉 @golang_lib