Где хранятся значимые типы (value types) в памяти в C#?

«Где хранятся значимые типы (value types) в памяти в C#?» — вопрос из категории Управление памятью, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Место хранения значимого типа зависит от контекста его объявления, а не от самого типа.

Основные случаи:

Контекст объявления Место хранения Пояснение и пример
Локальная переменная в методе Стек (Stack) Выделяется в стековом фрейме метода и очищается при его завершении.
void Method() { int x = 5; }
Поле класса или ссылочного struct Куча (Heap) Является частью памяти, выделенной для содержащего его объекта.
class MyClass { public int Value; }
Поле значимого struct Зависит от контекста родителя Хранится там же, где и экземпляр struct. Если struct в стеке — поле в стеке, если в куче — поле в куче.
Элемент массива Куча (Heap) Массивы являются ссылочными типами.
int[] arr = new int[10]; // 10 int'ов лежат в куче

Ключевые концепции:

  • Упаковка (Boxing): Когда значимый тип присваивается переменной типа object или интерфейса, он копируется в кучу. Это дорогая операция, которой следует избегать.
    int i = 123;
    object o = i; // Boxing: значение 'i' копируется в кучу.
  • Ref struct: Особый вид структур, которые могут находиться только в стеке и не могут быть упакованы (например, Span<T>, ReadOnlySpan<T>).