Кратко про основные различия (этого ответа достаточно на собеседовании):
🟰 Стек работает быстрее, потокобезопасен и имеет фиксированный размер. Управляется ОС. Хранит локальные переменные и аргументы функций.
💩 Память в куче динамически расширяемая и требует ручного управления или участия сборщика мусора. Может хранить глобальные переменные и ссылки (указатели).
🟰 Выделение памяти в стеке последовательно и фиксировано на этапе компиляции, и нельзя изменять размер стека после начала выполнения программы.
💩 Динамическое выделение в куче может привести к фрагментации памяти.
А теперь подробно.
Стек (Stack)
Аллокация памяти, другими словами, ее выделение происходит в стеке вызовов функций. Пространство памяти выделяется блоками. Компилятор знает размер памяти, который нужно выделить. Когда вызывается функция, память для её переменных выделяется в стеке и освобождается после завершения вызова функции.
Размер стека вызовов определяется многими факторами. Архитектура компьютера, на котором запущена программа, язык программирования и общий объем доступной системной памяти могут повлиять на размер программы. Если программа требует больше памяти, чем было выделено, это приведет к переполнению стека — stack overflow . В этой ситуации программа может зависнуть.
Стек работает в порядке LIFO (Last In, First Out), последний добавленный в стек кусок памяти будет первым в очереди на вывод из стека.
Куча (Heap)
Выделение памяти в куче происходит во время выполнения программы. В отличие от стека, память в куче выделяется динамически. Работа с памятью в куче контролируется программистом или сборщиком мусора (garbage collector). Сборщики мусора автоматически освобождают память, которая больше не используется программой.
Если не освободить неиспользуемую переменную, это может привести к утечке памяти. Утечка ухудшает производительность программы, так как занимаемое невысвобожденной переменной пространство, могло бы быть использовано для других частей программы.
Память кучи является глобальной. К ней можно получить доступ или изменить внутри программы по ссылке. В отличие от стека, она не ограничена функцией, в которой была выделена. Это делает выделение памяти в куче гибким, но не безопасным для потоков, так как любой, кто имеет ссылку, может читать и записывать данные.
Выделение памяти в куче значительно медленнее, чем в стеке, и приводит к фрагментации памяти, так как не является смежным. Но зато выделение памяти динамическое, что очень полезно во многих программах.
Escape analysis
Одна из фаз компилятора Go, которая анализирует код и определяет какие переменные должны быть аллоцированы в стек, а какие помещены в кучу. Команда для escape analysis запущенная в корне репозитория: