2010-11-03 1 views
4

Мне нужно выделить очень большие массивы простых структур (1 ГБ ОЗУ). После нескольких распределений/освобождений память становится фрагментированной и генерируется исключение OutOfMemory.C# chunked array

Это до 32 бит. Я бы предпочел не использовать 64-битный из-за штрафа за производительность, которое я получаю - одно и то же приложение работает на 30% медленнее в режиме 64 бит.

Знаете ли вы о некоторых реализациях совместимых с IList массивов, которые выделяют память в кусках, а не все сразу? Это позволит избежать проблемы фрагментации памяти.

+0

Нечетный, это * действительно * неправильный вопрос. Он должен был спросить: «Почему по 64-битной программе на 30% медленнее?» Ваш 32-битный процесс будет слишком длинным * слишком медленным после того, как вы обрезаете массивы. –

+0

Первоначально приложение было 64 бит, но после прочтения некоторых статей, которые свидетельствуют о том, что 64-разрядный JIT не так хорош в оптимизации кода, как 32-битный (http: // stackoverflow.com/questions/14432/64bit-net-performance-tuning), я преобразовал его в 32 бит и нашел, что это правда. Даже если я потеряю скорость здесь, он все равно начнет работать быстрее, чем 64-битная версия - я использую IronPython + C# + C++/CLI, а запуск 64-разрядной версии занимает 10 секунд (из-за IronPython) – Meh

ответ

3

Джош Уильямс представил BigArray<T> класс на своем блоге с помощью блочного массива:

BigArray<T>, getting around the 2GB array size limit

Вы найдете больше полезную информацию в этом связанном с этим вопрос:

C# huge size 2-dim arrays

Простым специальным исправлением может быть включение 3GB-переключателя для вашего приложения. Это позволяет вашему приложению использовать более чем 2 ГБ для каждого процесса в 32-разрядной Windows. Однако имейте в виду, что максимальный размер объекта, который разрешает CLR, по-прежнему составляет 2 ГБ. Переключатель может быть включен с помощью пост-встроенных действий для основного исполняемого файла:

call "$(DevEnvDir)..\tools\vsvars32.bat" 
editbin.exe /LARGEADDRESSAWARE "$(TargetPath)" 
+0

Я уже сделал трюк/LARGEADDRESSAWARE, и это помогло много – Meh

1

При вызове массива, .Net пытается найти смежную часть памяти для вашего массива. Поскольку общий предел памяти для 32-битного приложения составляет 2 ГБ, вы можете видеть, что будет трудно найти такой блок после нескольких распределений.

  1. Вы можете попробовать использовать что-то вроде LinkedList<T>, чтобы избежать необходимости непрерывного выделения, или реструктурировать свой код, чтобы сделать эти куски меньше (хотя вы не будете полностью безопасны, это не будет происходить с массивом 500Mb также).

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

  3. Если вы можете использовать IEnumerable вместо IList для передачи ваших данных в остальную часть вашей программы, вы сможете свернуть этот список, используя метод LINQ SelectMany.

  4. И в конце вы можете просто реализовать интерфейс IList в пользовательском классе и использовать несколько меньших массивов под капотом.

+0

+1 для # 2, простой и parsimonius – smirkingman