Прежде всего, давайте уточним, что мы подразумеваем под «кучей» против «стека».
Большинство современных сред программирования основаны на стеке.Когда вы запускаете программу, каждый раз, когда вы вызываете метод, новая запись помещается в специальный стек, предоставленный для вашей программы.Эта запись стека (или фрейм) сообщает системе, где искать исполняемый код метода, какие аргументы были переданы и куда именно возвращаться в вызывающем коде после выхода из метода.Когда метод завершается, его запись удаляется (выталкивается) из стека, поэтому программа может вернуться к предыдущему методу.Когда стек пуст, программа завершена.
Каждый кадр в стеке также имеет определенное количество места для локальных переменных для метода, а сам стек имеет ограниченный размер.Отсюда и «переполнение стека».Получите слишком много вызовов методов, стеку не хватит места.
Куча, с другой стороны, - это память, автоматически не предоставленная программе.Это память, которую программа должна запрашивать сверх выделенного ей ядра.Память кучи должна управляться более тщательно, но ее (как правило) гораздо больше.Поскольку он должен предоставляться операционной системой по запросу, начальные выделения из кучи также немного медленнее, чем выделения из стека.
В качестве широкого обобщения мы говорим о ссылочных типахраспределяются в куче, а типы значений распределяются в стеке (хотя для этого есть множество исключений).
Теперь, когда мы это много понимаем, мы можем начать смотреть на массивы.
Тип базового массива сам по себе является ссылочным типом. Я имею в виду, что для любого данного типа T
, T
может быть (или не быть) типом значения, но T[]
всегда является ссылочным типом.В контексте «стек против кучи» это означает, что создание нового массива является выделением кучи, даже если T
является типом значения.Массивы также имеют фиксированный размер.Это одиночное выделение кучи создаст достаточно места для всех элементов в массиве.
Дополнительной особенностью типов значений является то, что они имеют фиксированный размер, основанный на элементах.Таким образом, для массива у нас есть фиксированное количество элементов, каждый с известным фиксированным размером.Этого достаточно, чтобы получить все пространство для объекта массива и его элементов в одном выделении кучи.Значение каждого элемента хранится в памяти ядра массива.
Для массива, содержащего ссылочные типы, выделение кучи для массива создает пространство только для ссылок .Чтобы заполнить массив, вы должны сделать дополнительные выделения для каждого элемента.
Это может быть немного осложнено типом значения с одним или несколькими членами ссылочного типа.В этой ситуации пространство для типа значения выделяется как обычно, но часть значения для ссылочных элементов является просто ссылкой.Для создания объектов для этих ссылочных членов по-прежнему требуются отдельные выделения.