Ответ
Первый элемент массива хранится внутри самого объекта массива в управляемой куче (Managed Heap). Массив в .NET — это единый непрерывный блок памяти.
Как это устроено:
- При создании массива
new int[10]в куче выделяется один объект, который содержит:- Заголовок объекта (указатель на тип, sync block index).
- Длину массива.
- Непосредственно все элементы, расположенные друг за другом.
- Переменная массива в стеке хранит лишь ссылку на этот блок в куче.
- Сборщик мусора (GC) работает с массивом как с цельным объектом. Он не отслеживает ссылки на отдельные элементы.
Пример и важное следствие:
class Item { }
Item[] items = new Item[100];
items[0] = new Item(); // Созданный Item хранится ВНУТРИ массива `items`.
// Если ссылка `items` станет недостижимой,
// ВЕСЬ массив, включая все 100 элементов (ссылок), будет помечен для сборки.
Почему так? Это обеспечивает высокую производительность при итерации (элементы лежат в памяти последовательно — принцип локальности) и упрощает работу GC.
Ответ 18+ 🔞
А, слушай, вот тебе на самом деле интересный прикол про массивы в .NET. Многие думают, что там всё разрозненно летает, а на деле — полная противоположность.
Представь себе, создаёшь ты массив, ну, new int[10]. Так вот, в управляемой куче выделяется не десять отдельных ячеек, а один сплошной, цельный кусок памяти, как колбаса. В этом куске сразу всё и лежит: и служебная информация (что за тип, какая длина), и все десять твоих ячеек подряд, друг за дружкой.
Переменная в стеке — это просто бумажка с адресом, где эта "колбаса" начинается. И самое главное — для сборщика мусора массив это единый объект. Он не будет ковыряться внутри, проверяя, а живы ли отдельные элементы. Нет, блядь.
Вот смотри, пример-то какой наглядный:
class Item { }
Item[] items = new Item[100];
items[0] = new Item(); // Созданный Item хранится ВНУТРИ массива `items`.
Ты создал массив на 100 ссылок. Потом в первую ячейку положил реальный объект Item. Где он физически? Да внутри этого самого блока памяти массива! Всё в одной куче, в одном месте.
И вот теперь ключевой момент: если твоя переменная items выйдет из области видимости и на неё никто больше не будет ссылаться, то сборщик мусора придет и скажет: "А, этот цельный кусок памяти больше не нужен". И вынесет его нахуй целиком, со всеми ста ячейками, даже если в некоторых из них были ссылки на другие объекты. Потому что массив — это один объект. Не набор, а один.
А сделано так, ёпта, для скорости, чтоб итерироваться было быстро. Элементы-то в памяти подряд лежат, процессору их подгружать удобно. И GC тоже проще — меньше головной боли с отслеживанием связей. Гениально и просто, как всё гениальное.