Где в Go хранятся переменные, созданные внутри функции?

Ответ

В Go, в отличие от языков вроде C++, программист не решает напрямую, где будет размещена переменная. Это решение принимает компилятор на основе анализа побега (escape analysis).

Переменная, объявленная в функции, может быть размещена либо в стеке (stack), либо в куче (heap).

  1. Стек (Stack)

    • Это местоположение по умолчанию для локальных переменных. Память в стеке выделяется и освобождается очень быстро (при входе и выходе из функции).
    • Переменная остается в стеке, если компилятор доказывает, что указатель на эту переменную не "сбегает" из функции, то есть не используется после того, как функция завершит свою работу.
    func main() {
        x := 42 // 'x' скорее всего будет в стеке
        fmt.Println(x)
    } // Память под 'x' освобождается здесь
  2. Куча (Heap)

    • Если компилятор обнаруживает, что на переменную будут ссылаться после завершения функции, он размещает её в куче. Память в куче управляется сборщиком мусора (Garbage Collector).
    • Это называется "побегом" переменной (variable escapes to the heap).

    Примеры, когда переменная "сбегает" в кучу:

    • Возврат указателя на локальную переменную:

      func createInt() *int {
          x := 10 // 'x' "сбежит" в кучу, т.к. указатель на неё возвращается
          return &x
      }
    • Переменная используется в замыкании (closure), которое переживает функцию:

      func counter() func() int {
          n := 0 // 'n' "сбежит" в кучу, т.к. используется в возвращаемой функции
          return func() int {
              n++
              return n
          }
      }

Вывод: Место хранения (стек или куча) определяется не синтаксисом (var, :=, new), а тем, как переменная используется в коде. Компилятор Go автоматически оптимизирует размещение для баланса между производительностью (стек) и корректностью управления памятью (куча).