Управление памятью для каждого потока в C#

Продолжая обсуждение с Понимание результатов параллельного профилирования VS2010 C#, но ближе к делу:

У меня есть много потоков, которые работают параллельно (используя Parallel.For/Each), которые используют много выделений памяти для небольших классов.

Это создает конкуренцию в глобальном потоке распределителя памяти.

Есть ли способ указать .NET предварительно выделить пул памяти для каждого потока и выполнить все выделения из этого пула?

В настоящее время моим решением является моя собственная реализация пулов памяти (глобально выделенные массивы объектов типа T, которые перерабатываются между потоками), что очень помогает, но неэффективно, потому что:

  1. Я не могу указать .NET выделить из определенного фрагмента памяти.
  2. Мне по-прежнему нужно много раз вызывать new, чтобы выделить память для пулов.

Спасибо,
Аггей


person Haggai    schedule 26.05.2010    source источник
comment
Можно ли сделать T типом значения и разместить его в стеке, а не в куче?   -  person Eric Mickelsen    schedule 26.05.2010
comment
В чем проблема? Ваше программирование работает медленно? Нехватка памяти, т.е. сбой? Просто используете много памяти?   -  person Lasse V. Karlsen    schedule 26.05.2010
comment
@tehMich: я так не думаю. Эти объекты являются составными классами, и разбивать их на отдельные переменные или массивы было бы обременительно. Кроме того, они нужны в больших количествах, которые, я не уверен, поместятся в стеке (я говорю о десятках мегабайт).   -  person Haggai    schedule 26.05.2010
comment
@ Лассе В. Карлсен: проблема заключается в разногласиях по распределению памяти, что замедляет работу программы.   -  person Haggai    schedule 26.05.2010


Ответы (3)


Я искал два дня, пытаясь найти ответ на ту же проблему, что и у вас. Ответ: вам нужно установить режим сборки мусора в режим сервера. По умолчанию режим сборки мусора установлен в режим рабочей станции. При установке сбора мусора в режим сервера управляемая куча разбивается на разделы, управляемые отдельно, по одному на ЦП. Для этого вам нужно добавить параметр конфигурации в файл app.config.

<runtime>
   <gcServer enabled="true"/>
</runtime>

Разница в скорости на моем 12-ядерном Opteron 6172 была разительной!

person Craig Peters    schedule 06.06.2011
comment
Теперь это новость, никогда не знал, что можно так настроить GC. Я сделаю это в своем собственном коде, очень интересно посмотреть, что он будет делать! - person gjvdkamp; 06.06.2011

Сборщик мусора не выделяет память.

Это больше похоже на то, что вы выделяете множество небольших временных объектов и несколько долгоживущих объектов, а сборщик мусора тратит много времени на сборку временных объектов, поэтому вашему приложению не нужно запрашивать больше памяти у ОПЕРАЦИОННЫЕ СИСТЕМЫ. Из Расширенная разработка .NET Framework 4 — сборка мусора:

Пока в управляемой куче доступно адресное пространство, среда выполнения продолжает выделять место для новых объектов. Однако память не безгранична. В конце концов сборщик мусора должен выполнить сборку, чтобы освободить часть памяти.

Решение: Не выделяйте много небольших временных объектов. Страница на Сборка мусора и производительность также могут быть полезны.

person tc.    schedule 26.05.2010
comment
Требования к памяти для моего приложения действительно велики (несколько гигабайт), но у меня 8 ГБ ОЗУ, а сеанс сбора GC происходит только раз в минуту или около того и очень короткий. - person Haggai; 26.05.2010
comment
Сеанс сбора GC происходит только один раз в минуту или около того, и кажется, что он очень короткий, что противоречит тому, что большая часть времени синхронизации была потрачена на ожидание завершения потока GC для выделения памяти из вашего другого сообщения. - person tc.; 31.05.2010

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

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

person Guffa    schedule 26.05.2010
comment
Ваш первый абзац - это как раз мое текущее решение. Поскольку я повторно использую эти объекты в своей программе много раз для многих потоков, я считаю, что копирование в кучу второго поколения в этом случае незначительно. Как я могу проверить, так ли это? - person Haggai; 26.05.2010