Выделение памяти из больших структур данных в C # - PullRequest
4 голосов
/ 20 сентября 2010

В моем коде моделирования есть несколько структур SortedList<> и SortedDictionary<>, и со временем я добавляю в них миллионы элементов.Проблема в том, что сборщик мусора не освобождает достаточно быстро память, поэтому производительность приложения сильно ухудшается.Моим последним вариантом было задействовать метод GC.Collect(), чтобы я мог вернуть эту память обратно.У кого-нибудь есть другая идея?Мне известен шаблон Flyweight, который является еще одним вариантом, но я был бы признателен за другие предложения, которые не требовали бы огромного рефакторинга моего кода.

Ответы [ 4 ]

4 голосов
/ 20 сентября 2010

Вы боретесь с принципом "Там нет бесплатного обеда".Вы не можете предполагать, что добавление миллионов элементов в список не повлияет на производительность.Только SortedList <> должен быть проблемой, он начнет выделять память в куче больших объектов.Это распределение не будет освобождено в ближайшее время, требуется сборка № 2 поколения, чтобы снова выбросить вещи из LOH.В противном случае эта задержка не должна влиять на производительность вашей программы.

Единственное, что вы можете сделать, - это избежать нескольких копий внутреннего массива, который SortedList <> будет застревать в LOH, когда он будет расти.Попробуйте угадать хорошее значение для Capacity, чтобы он заранее выделил большой массив.

Далее, используйте Perfmon.exe или TaskMgr.exe и посмотрите на ошибку страницы вашей программы.Он должен быть довольно занят, пока вы распределяете.Если вы видите низкие значения (100 или меньше), то у вас может быть проблема с фрагментацией файла подкачки.Обычное зло на старых машинах под управлением XP.Дефрагментация диска и использование утилиты PageDefrag от SysInternals могут сделать удивительные чудеса.

3 голосов
/ 21 сентября 2010

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

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

Эту проблему можно решить, разбив большие объекты на более мелкие фрагменты.

2 голосов
/ 20 сентября 2010

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

О каком снижении производительности идет речь и о какой операционной системе?Если я помню, GC будет работать, когда это необходимо, а не сразу или даже «скоро».Поэтому диспетчер задач, показывающий большое количество памяти, выделенной вашему приложению, не обязательно является проблемой.Что произойдет, если вы загрузите компьютер с более высокой нагрузкой (например, запустите несколько копий своего приложения)?В этом сценарии память восстанавливается быстрее или у вас заканчивается память?

Надеюсь, ответы на эти вопросы помогут вам указать верное направление.

1 голос
/ 20 сентября 2010

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

Если вам нужно собрать элементы в структурах, вынеобходимо удалить их из структуры данных.

Чтобы очистить всю структуру данных, попробуйте использовать Clear() и установить ссылку на структуру данных на null.Если данные все еще не собираются достаточно быстро, звоните CC.Collect().

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