Стоит ли инициализировать размер коллекции List ‹T›, если его размер достаточно известен?

Стоит ли инициализировать размер коллекции List<T>, если он достаточно известен?

Изменить: Продолжая этот вопрос, после прочтения первых ответов этот вопрос действительно сводится к тому, какова емкость по умолчанию и как выполняется операция увеличения, удваивает ли она емкость и т. д.?


person Chris Marisic    schedule 11.02.2010    source источник
comment
Просто по тому, что вы сказали разумно, а не определенно, я бы сказал нет.   -  person Nate W.    schedule 12.02.2010
comment
По какому критерию вы бы определили сусло? Если просто ускорите, запустите несколько тестов и сообщите нам результаты, пожалуйста :-) IIRC Список удваивается каждый раз, когда он заполняется (двоичная прогрессия), поэтому есть некоторые накладные расходы на это   -  person TFD    schedule 12.02.2010
comment
Reflector может ответить на вопросы в вашей редакции (ответы будут 0 и да (кроме 0 - ›4 в первый раз))   -  person AakashM    schedule 12.02.2010
comment
@NateW. Я бы сказал, инициализируйте его до самого низкого предела, в котором вы уверены.   -  person Luis Filipe    schedule 30.01.2017


Ответы (3)


Да, это становится важным, когда ваш List<T> становится большим. Точные числа зависят от типа элемента и архитектуры машины, давайте выберем Список ссылочных типов на 32-битной машине. Затем каждый элемент займет 4 байта во внутреннем массиве. Список начнется с емкости 0 и пустого массива. Первый Add() вызов увеличивает емкость до 4, перераспределяя внутренний массив до 16 байтов. Спустя четыре Add() вызова массив заполнен, и его необходимо снова перераспределить. Он увеличивает размер вдвое, емкость увеличивается до 8, размер массива до 32 байтов. Предыдущий массив - мусор.

Это повторяется по мере необходимости, несколько копий внутреннего массива станут мусором.

Что-то особенное происходит, когда массив увеличивается до 65 536 байт (16 384 элемента). Следующая функция Add () снова удваивает размер до 131 072 байта. Это выделение памяти, превышающее пороговое значение для «больших объектов» (85 000 байт). Распределение теперь больше не выполняется в куче поколения 0, оно берется из кучи больших объектов.

Особо обрабатываются объекты на LOH. Они только собираются мусором во время сборки поколения 2. И куча не уплотняется, перемещение таких больших кусков занимает слишком много времени.

Это повторяется по мере необходимости, несколько объектов LOH станут мусором. Они могут занимать память довольно долго, коллекции поколения 2 бывают нечасто. Другая проблема заключается в том, что эти большие блоки имеют тенденцию фрагментировать адресное пространство виртуальной памяти.

Это не повторяется бесконечно, рано или поздно классу List необходимо перераспределить массив, и он стал настолько большим, что в адресном пространстве виртуальной памяти не осталось дыры для размещения массива. Ваша программа будет бомбить OutOfMemoryException. Обычно задолго до того, как вся доступная виртуальная память будет израсходована.

Короче говоря, установив емкость заранее, до того, как вы начнете заполнять список, вы можете заранее зарезервировать этот большой внутренний массив. Вы не получите все эти неудобно выпущенные блоки в куче больших объектов и избежите фрагментации. Фактически, вы сможете хранить гораздо больше объектов в списке, и ваша программа будет работать более компактно, поскольку там так мало мусора. Делайте это только в том случае, если вы хорошо представляете, насколько большим будет список, использование большой емкости, которую вы никогда не заполните, будет расточительным.

person Hans Passant    schedule 11.02.2010
comment
Очень информативный ответ, я не думаю, что мне когда-либо приходилось работать со списками, содержащими более 10 000 элементов, но теперь, если я когда-нибудь думаю, что мне понадобятся эти знания, они будут очень полезны, чтобы понять последствия таких больших списков. - person Chris Marisic; 12.02.2010
comment
Интересно видеть мой комментарий десятилетней давности, который до сих пор работал с массивами, охватывающими 5 миллиардов индексов. - person Chris Marisic; 24.01.2019

Это согласно документации

Если размер коллекции можно оценить, указание начальной емкости устраняет необходимость выполнять ряд операций по изменению размера при добавлении элементов в список (T).

person Asad    schedule 11.02.2010
comment
Я думаю, что это 0. Можно проверить в любое время с помощью List (T) .Capacity prop - person Asad; 12.02.2010

Что ж, это избавит вас от необходимости периодически копировать значения в списке (которые будут ссылками, если тип элемента является ссылочным) по мере роста списка.

Если это будет особенно большой список, и вы довольно хорошо представляете его размер, это не повредит. Однако, если оценка размера включает в себя дополнительные вычисления или какой-либо значительный объем кода, я бы не стал беспокоиться об этом, если вы не обнаружите, что это становится проблемой - это может отвлекать от основного внимания кода, а изменение размера вряд ли приведет к повышению производительности. проблемы, если это не действительно большой список или вы не занимаетесь этим много.

person Jon Skeet    schedule 11.02.2010