Стоит ли инициализировать размер коллекции List <T>, если он достаточно известен? - PullRequest
35 голосов
/ 12 февраля 2010

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

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

Ответы [ 3 ]

68 голосов
/ 12 февраля 2010

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

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

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

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

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

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

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

19 голосов
/ 12 февраля 2010

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

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

8 голосов
/ 12 февраля 2010

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...