Управление памятью для каждого потока в C#
Продолжаем обсуждение из раздела Понимание результатов параллельного профилирования VS2010 C#, но ближе к делу:
У меня есть много потоков, которые работают параллельно (используя Parallel.For/Each), которые используют много выделения памяти для небольших классов.
Это создает конфликт в потоке распределителя глобальной памяти.
Есть ли способ дать указание.NET предварительно выделить пул памяти для каждого потока и выполнить все выделения из этого пула?
В настоящее время моим решением является моя собственная реализация пулов памяти (глобально распределенных массивов объекта типа T, которые перерабатываются между потоками), что очень помогает, но неэффективно, потому что:
- Я не могу дать указание.NET выделить из определенного фрагмента памяти.
- Мне все еще нужно вызывать новый много раз, чтобы выделить память для пулов.
Спасибо,
Аггей
3 ответа
Я искал два дня, пытаясь найти ответ на ту же проблему, что и у вас. Ответ: вам нужно установить режим сбора мусора в режим сервера. По умолчанию режим сбора мусора установлен в режим рабочей станции. При установке сборки мусора в режим сервера управляемая куча разделяется на отдельные управляемые разделы, по одному на процессор. Для этого вам нужно добавить параметр конфигурации в ваш файл app.config.
<runtime>
<gcServer enabled="true"/>
</runtime>
Разница в скорости на моем 12-ядерном Opteron 6172 была впечатляющей!
Вы можете предварительно выделить кучу объектов и хранить их в группах, предназначенных для отдельных потоков. Тем не менее, вероятно, что от этого вы не достигнете лучшей производительности.
Сборщик мусора специально разработан для эффективной обработки небольших недолговечных объектов. Если вы храните объекты в пуле, они являются долгоживущими и выживут при сборе мусора, что, в свою очередь, означает, что они будут скопированы в кучу второго поколения. Это копирование будет дороже, чем просто выделение новых объектов.
Сборщик мусора не выделяет память.
Это больше похоже на то, что вы выделяете много маленьких временных объектов и несколько долгоживущих объектов, а сборщик мусора тратит много времени на сбор мусора временных объектов, поэтому вашему приложению не нужно запрашивать больше памяти у ОПЕРАЦИОННЫЕ СИСТЕМЫ. Из .NET Framework 4 Advanced Development - Сборка мусора:
Пока в управляемой куче доступно адресное пространство, среда выполнения продолжает выделять пространство для новых объектов. Однако память не бесконечна. В конце концов сборщик мусора должен выполнить сборку, чтобы освободить часть памяти.
Решение: не выделяйте много маленьких временных объектов. Также может быть полезна страница " Сборка мусора и производительность".