2010-06-27 2 views
8

У меня есть довольно простое приложение C#, которое создает большую хеш-таблицу. Ключами этой хэш-таблицы являются строки, а значения - int.Почему было бы исключено исключение из памяти, если доступна память?

Программа отлично работает, пока в хеш-таблицу не добавится около 10,3 млн. Элементов, когда в строке добавляется ошибка с памятью, которая добавляет элемент в таблицу hasbtable.

Согласно диспетчеру задач, моя программа использует только 797 МБ памяти, и все еще доступно более 2 ГБ. Это 32-разрядная машина, поэтому я знаю, что только один 2gb может использоваться одним процессом, но это все равно оставляет около 1,2 гб, что хэш-таблица должна быть в состоянии расшириться.

Зачем возникла ошибка в памяти?

+1

Кстати, я надеюсь, вы понимаете, что это не имеет ничего общего с C#? –

+0

@John: но, возможно, возможно, это связано с .net. – Wizard79

+0

@ Lorenzo: вот моя точка. Не C#, но .NET. –

ответ

11

В теории вы получаете 2 Гб для процесса, но реальность такова, что это 2 ГБ непрерывной памяти, поэтому, если память вашего процесса фрагментирована, вы получаете меньше этого.

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

Если вам известен размер, который должен быть досрочно (или иметь разумную переоценку), это может помочь указать емкость в конструкторе.

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

+1

Не совсем: каждый процесс имеет свою приватную виртуальную память объемом 2 ГБ. Фрагментация * внутри * процесса, потому что две непрерывные страницы памяти в вашем процессе могут фактически не быть смежными с ядром. – Wizard79

+0

Спасибо ... Я запустил его снова с мощностью в 17 миллионов, и мы посмотрим, как это получится. Данные поступают из базы данных, но я не могу запускать процедуру там, так как рекурсивные запросы очень медленные. Я мог бы вставить каждый экземпляр (item, node) в базу данных для его обработки после, но я ожидаю, что он будет очень медленным из-за скорости сети. – Paul

+0

@Lorenzo Спасибо, обновлено, чтобы отразить, что это фрагментация памяти в процессе, а не система. – Davy8

4

Возможно, это связано с фрагментацией памяти: у вас есть свободная память, но не непрерывная. Память делится на страниц, как правило, 4 КБ, поэтому, если вы выделите 4 МБ, вам понадобится 1024 смежных страниц памяти в вашем обращении к пространству (они не являются физически смежным, поскольку память виртуализирована per- обработать).

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

0

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

3

Используйте Process Explorer (www.sysinternals.com) и посмотрите на виртуальное адресное пространство вашего процесса. В отличие от «Private Bytes» (который является объемом памяти, занятой процессом) виртуальное адресное пространство показывает наивысший адрес памяти. Если фрагментация высока, она будет намного выше, чем «Частные байты».

Если ваше приложение действительно нуждается в этой большой объем памяти:

  • Рассмотрим собирается 64-битный
  • Включить флаг/LARGEADDRESSAWARE, который даст свой 32-битный процесс 4 Гб оперативной памяти под 64-битную операционной системы и 3 ГБ, если 32-разрядная Windows загружается с флагом/3GB.
1

Вы просто смотрите на неправильную колонку. Посмотрите на столбец «Commit Size», это должно быть около 2 ГБ.

http://windows.microsoft.com/en-us/windows-vista/What-do-the-Task-Manager-memory-columns-mean

+0

Это Windows XP ... Я не думаю, что он имеет «Commit Size» в диспетчере задач – Paul

+0

Это приятный ответ, однако теперь возникает вопрос: почему размер фиксации больше, чем фактическое использование памяти? – Wizard79

+0

Lorenzo: «Commit size» - объем памяти, зарезервированный для использования приложением (т. Е. Команда выделения памяти) - не обязательно означает, что она фактически используется. «Частный рабочий набор» - это объем памяти, который был выделен/и/использован процессом, который не может быть передан другим процессам. –

1

Программа вы работаете имеет ограниченные ресурсы благодаря Visual Studio отладчик пытается отслеживать все, что вы делаете в вашем приложении (контрольные точки, ссылки, стек и т.д.).

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

+-------+ 
    | large |  collected less often (~1/10+ cycles) 
    +-+-------+-+    | 
    | medium |    | 
+-+-----------+-+   V 
|  small  | collected more often (~1/3 cycles) 
+---------------+ 

ПРИМЕЧАНИЕ: Цифры взяты из памяти, поэтому возьмите его с солью.

+0

-1: Почему вы думаете, что он работает в отладчике? –

+0

Позвольте мне уточнить, что работает в режиме отладки, а не в режиме деблокирования. – Tim

0

Я решил свою версию этой проблемы, сняв флажок «Предпочитают 32-бит» в странице свойств проекта ехе под вкладку Построить

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