Ответ
Разница фундаментальна и касается выделения, времени жизни и размера памяти.
| Характеристика | Стек (Stack) | Куча (Heap) |
|---|---|---|
| Что хранится | Значимые типы (Value Types): int, bool, struct, а также ссылки на объекты в куче. |
Ссылочные типы (Reference Types): экземпляры class, массивы, строки (string). |
| Управление памятью | Автоматическое, по LIFO. Память освобождается мгновенно при выходе из области видимости (метода). Крайне быстро. | Управляется сборщиком мусора (GC). Память освобождается не сразу, а когда GC решит, что объект больше не нужен. Это создает паузы. |
| Скорость выделения | Очень высокая. Просто сдвигается указатель стека. | Относительно ниже. Требуется поиск свободного блока и синхронизация потоков. |
| Размер | Ограничен (обычно ~1 МБ на поток по умолчанию в .NET). Превышение приводит к StackOverflowException. |
Огромен. Ограничен только доступной виртуальной памятью ОС. |
| Фрагментация | Нет. | Возможна. GC проводит компрессию (уплотнение) для ее борьбы. |
Практический пример и важные нюансы:
void Example()
{
int number = 42; // Значимый тип 'int' размещается в СТЕКЕ.
object obj = new object(); // 1. Экземпляр 'object' создается в КУЧЕ.
// 2. Ссылка 'obj' (адрес в памяти) размещается в СТЕКЕ.
} // При выходе из метода:
// - 'number' и ссылка 'obj' автоматически удаляются из стека.
// - Сам объект в куче помечается для будущей сборки мусора.
Ключевые исключения (где value type может оказаться в куче):
- Упаковка (Boxing):
int i = 10; object boxed = i; - Поля ссылочного типа: Поле
intвнутриclassхранится в куче вместе с экземпляром класса. - Захват в замыкании или асинхронном методе.
- Большие структуры могут быть неявно размещены в куче для оптимизации производительности.