Ответ
Сборщик мусора (Garbage Collector, GC) в Go работает исключительно с кучей (heap).
Разберёмся почему:
Стек (Stack)
- Память на стеке выделяется для локальных переменных функции (аргументы, переменные, объявленные внутри функции).
- Время жизни этих переменных строго ограничено временем выполнения функции.
- Память освобождается автоматически при выходе из функции (по принципу LIFO — Last In, First Out). Управление стеком очень быстрое и детерминированное, GC здесь не нужен.
Куча (Heap)
- Память в куче выделяется для данных, время жизни которых не связано с конкретным вызовом функции. Это данные, которые должны "пережить" функцию, в которой были созданы.
- В Go компилятор с помощью анализа побега (escape analysis) решает, где выделить переменную: на стеке или в куче. Если компилятор видит, что на переменную берётся указатель, который возвращается из функции, эта переменная "сбегает" в кучу.
- Именно за объектами в куче и следит GC. Он периодически сканирует память, находит объекты, на которые больше нет ссылок (из стеков горутин или глобальных переменных), и освобождает занимаемое ими место.
Пример с анализом побега:
func createInt() *int {
// Компилятор видит, что ссылка на 'x' возвращается наружу.
// Поэтому 'x' будет выделена в куче, а не на стеке.
x := 42
return &x
}
func main() {
// ptr указывает на память в куче.
// Когда ptr выйдет из области видимости (или станет nil),
// GC сможет освободить память, где хранилось значение 42.
ptr := createInt()
fmt.Println(*ptr)
}