2

У меня есть многопоточное приложение, которое управляет данными в памяти (без доступа к базе данных или сети). Я попробовал это на двух машинах, одна машина - двухъядерный процессор Xeon с четырьмя ядрами, а другой - двухжильные. Создано 5 нитей.C# многопоточность использования памяти - замедление работы приложений и падение использования процессора

Затем этот многопоточный процесс запускается очень быстро, а загрузка процессора составляет 60% для 5 ядер, физическая память составляет 50% от объема оперативной памяти. (Информация из диспетчера задач). После того, как он достигнет 1/3 пути, он начинает замедляться, а загрузка процессора падает чуть ниже 20%. К тому времени, когда он дойдет до 2/3, он так медленно, что для завершения последней трети требуется 1 день, а для первого 1/3 требуется полчаса.

Процесс создает много SortedLists и Lists, поэтому я начинаю подозревать, что сборщик мусора не справляется, хотя использование памяти диспетчера задач не так уж плохо ... Я хочу попытаться заставить GC бесплатно неиспользованные коллекции немедленно, это разумно или даже выполнимо? И почему загрузка процессора падает?

+1

Google "блокировка конвоя". –

ответ

1

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

Загрузите инструмент, как Memprofiler, Ants или dotTrace (все они имеют пробные версии), чтобы определить, является ли вы утечкой памяти. Вы выделяете объекты размером более 85 КБ?

Кроме того, какую версию ОС и .NET Framework вы используете? (Существуют различия в том, как сервер и PC версии GC работала)

Кроме того, следует помнить, что вставка в SortedList является O (N) (в то время как SortedDictionary вставки O (LogN):

общий класс SortedList является бинарного дерева поиска с O (Log п) поиска, где п числом элементов в словаре. в этом он похож на универсальный класс SortedDictionary . Эти два класса имеет аналогичные объектные модели, и оба имеют O (log n), где два классы различаются в использовании памяти и скорость вставки и удаления:

  • SortedList использует меньше памяти, чем SortedDictionary.

  • SortedDictionary имеет более быструю вставку и операции по удалению для несортированных данных, вывод (журнал N), в отличие от O (N) для SortedList.

  • Если список заселен все сразу из отсортированных данных, SortedList быстрее than SortedDictionary.

Ref.

Как вы управляете многопоточным доступом к этим спискам? Можете ли вы опубликовать некоторый код сокращения?

+0

+1 для форсирования gc – Rob

+0

Я использую XP Professional SP2, с .NET 3.5, который, как мне известно, такой же, как и 2.0 ядра. Списки, которые я строю, длинны, но они содержат целые числа и парные. Сами списки больше, чем 85K, я уверен. – Misha

+0

Да, это правильное направление. Мне нужно загрузить профилировщик и выяснить, как его использовать, o/w его просто сотрясают в темноте. – Misha

1

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

Чтобы проверить GC, запустите perfmon и просмотрите (или запишите) счетчики производительности для сборщика мусора и распределения памяти.

+0

Это справедливо для многих сценариев, но здесь размер списка не увеличивается по итерациям - он отбрасывается и перестраивается каждый раз, поэтому его длина не увеличивается ... Мне нужно посмотреть в perfmon – Misha

+0

Собственно, Im ll - есть список результатов, который используется во всех потоках, но его длина составляет всего три единицы, поэтому я не думаю, что это проблема. – Misha

+0

@Misha: это может быть, если все потоки пытаются получить к нему доступ часто. –

0

Звучит как проблема блокировки структуры данных. Трудно сказать, не зная, что именно вы делаете.

Попробуйте использовать одну из незакрепленных несвязанных коллекций, таких как ConcurrentDictionary или ConcurrentBag и/или соответствующую очередь, такую ​​как BlockingCollection.

0

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

0

60% процессор на 5 сердечников из 5 потоков. Я предполагаю, что это 60% на каждый ядро. Это на самом деле очень плохо. Вы не можете управлять ЦП до 100%, выполняя только операцию с памятью (без базы данных, без сети, без файла IO), это означает, что ваше утверждение о блокировке огромно. По мере того, как программа прогрессирует, ваши структуры предположительно растут по размеру (больше элементов в некоторых списках/словарях), вы удерживаете блокировки дольше, а результат меньше процессор и даже более медленная производительность.

Трудно сказать без каких-либо реальных данных о производительности, но это не похоже на связанные с GC. Это больше похоже на высокий конфликт в структурах данных. Вы должны проследить свое приложение под профилировщиком и посмотреть, где больше всего тратится процессор/время ожидания. См. Pinpoint a performance issue using hotpath in Visual Studio 2008 для быстрого ознакомления с профилировщиком пробоотбора.

+0

Ремус, это очень полезно. Я не вижу вид вызова в VS2008? Нужно ли сначала загрузить его с MS? – Misha

+0

Я думаю, что это только в VSTS 2008, Ultimate и Premium 2010. Standard 2008/2010 этого не имеет. http://msdn.microsoft.com/en-us/library/ms182372.aspx –

Смежные вопросы