Оптимизация памяти коллекций .net - будет ли этот метод работать? - PullRequest
5 голосов
/ 29 января 2011

Как и почти любое другое большое приложение .NET, мой текущий проект C# содержит множество коллекций .net.
Иногда я не знаю с самого начала, каким будет размер Коллекции (List / ObservableCollection / Dictionary / etc.).
Но много раз я знаю, что это будет.

Я часто получаю OutOfMemoryException, и мне сказали, что это может произойти не только из-за ограничений размера процесса, но и из-за фрагментации.

Итак, мой вопрос таков: поможет ли установка размера коллекции (используя аргумент емкости в конструкторе) каждый раз, когда я знаю, что ее ожидаемый размер поможет мне предотвратить хотя бы некоторые проблемы фрагментации?

Это цитата из MSDN :

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

Но, тем не менее, я не хочу начинать заменять большие части моего кода на что-то, что может быть не настоящей проблемой.

Помогло ли вам когда-нибудь решение проблем с памятью?

Ответы [ 5 ]

4 голосов
/ 29 января 2011

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

Однако, 99 из 100, у вас утечка памятипроблемы изменения размеров приложений и коллекций - это только ее симптом.

3 голосов
/ 29 января 2011

Если вы нажимаете OOM, возможно, вы чрезмерно агрессивны с данными, но для ответа на вопрос:

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

Начиная с правильного размера, запрещаются все промежуточные копии массива.

Однако, это также зависит от того, что в массив имеет значение. Как правило, для классов имеется больше данных в каждом объекте (плюс накладные расходы для ссылок и т. Д.) - это означает, что список не обязательно является основным виновником использования памяти; Вы, возможно, сжигаете большую часть памяти на объектах.

Обратите внимание, что x64 предоставит больше общего пространства, но массивы ограничены 2 ГБ - и если каждая ссылка удваивается в размере, это уменьшает вдвое максимальную эффективную длину массива.

Лично я хотел бы разбить огромные множества на более мелкие цепочки списков; зубчатые списки, например.

2 голосов
/ 29 января 2011

.NET имеет сборочный сборщик мусора, так что вы, вероятно, не столкнетесь с проблемами фрагментации в обычной куче .NET.Однако вы можете получить фрагментацию памяти, если используете много неуправляемой памяти (например, через GDI +, COM и т. Д.).Кроме того, куча больших объектов не сжимается, что также может привести к фрагментации.IIRC объект помещается в LOH, если он больше 80 КБ.Поэтому, если у вас много коллекций, содержащих более 20 тыс. Объектов, вы можете получить проблемы фрагментации.

Но вместо того, чтобы угадывать, где может быть проблема, может быть лучше сузить проблемуеще немного: когда вы получаете исключения OutOfMemoryException?Сколько памяти использует приложение в это время?Используя такой инструмент, как WinDbg или профилировщики памяти, вы сможете узнать, сколько этой памяти находится на LOH.

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

1 голос
/ 29 января 2011

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

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

Фрагментация может происходить только на LOH (объекты размером более 80 кБ). Чтобы предотвратить это, попробуйте выделить блоки одинакового размера. Как ни парадоксально, решение может заключаться в том, чтобы иногда выделять больше памяти, чем вам действительно нужно.

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