Фрагментация в C++ с большими порциями данных (Windows)

Я разрабатывал свою программу, используя malloc() выделить память. Однако мои исследования заставили меня думать, что я столкнулся с проблемой фрагментации памяти.

Моей программе нужно 5 выделений памяти ~70 МБ каждый. Когда я запускаю свою программу, используя 4 потока, мне нужно 5x4 выделения памяти ~70 МБ каждый (и я не могу использовать меньше памяти). В конце я хочу использовать 8 ядер моего i7, это 5x8.

Если я выполняю 5x2 malloc(), программа работает. Не для 5x3 malloc()s.

Я читал о std::vector а также std::deque, я полагаю, что std::deque мое решение для этой проблемы, как std::vector выделяет большой кусок последовательной памяти как malloc() делает.

Есть ли другие решения для изучения или std::deque мое единственное решение?


РЕДАКТИРОВАТЬ

ОС: Windows 8.1 (x64)

Оперативная память: 8 ГБ (5 ГБ свободного места)

Я обнаруживаю malloc() ошибки путем проверки errno == ENOMEM


НОТА: ERROR_MEM_ALLOC_FAILED является одной из ошибок, которые я генерирую, когда распределение памяти не удается.

Трасса отладки для программы с 4-мя потоками (т.е. 5x4 malloc()s):

Start

Thread 01
(+53.40576 MB) Total allocated  53.4/4095 total MB
(+53.40576 MB) Total allocated 106.8/4095 total MB
(+0.00008 MB)  Total allocated 106.8/4095 total MB
(+0.00008 MB)  Total allocated 106.8/4095 total MB
Tried to allocate 267 MB
ERROR_MEM_ALLOC_FAILED

Thread 02
(+53.40576 MB) Total allocated 160.2/4095 total MB
(+53.40576 MB) Total allocated 213.6/4095 total MB
(+0.00008 MB)  Total allocated 213.6/4095 total MB
(+0.00008 MB)  Total allocated 213.6/4095 total MB
Tried to allocate 267 MB
ERROR_MEM_ALLOC_FAILED

Thread 03
(+53.40576 MB) Total allocated 267.0/4095 total MB
Tried to allocate 53 MB
ERROR_MEM_ALLOC_FAILED

Thread 04
Tried to allocate 53 MB
ERROR_MEM_ALLOC_FAILED

End of program

Я попытался запустить то же самое, но изменил порядок распределения памяти, но память не была выделена.

Start

Thread 01
Tried to allocate 267 MB
ERROR_MEM_ALLOC_FAILED

Thread 02
Tried to allocate 267 MB
ERROR_MEM_ALLOC_FAILED

Thread 03
Tried to allocate 267 MB
ERROR_MEM_ALLOC_FAILED

Thread 04
Tried to allocate 267 MB
ERROR_MEM_ALLOC_FAILED

End of program

РЕШЕНИЕ

Решением было скомпилировать приложение как 64-битное приложение. Следовательно, вероятно, это была не проблема фрагментации.

2 ответа

Решение

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

Кроме того, этот объем памяти невелик по сегодняшним стандартам, хотя это зависит от вашего оборудования и операционной системы. Сколько физической памяти у вашей машины? На какой ОС вы работаете? Это как 32-битное или 64-битное приложение? Откуда вы знаете malloc терпит неудачу - это возвращается null? Вы пробовали профилирование памяти?

Heap usage: 8 threads * 5 blocks * 70MB per block = 2800MB total

В Windows ограничение по умолчанию для каждого процесса для выделения кучи составляет 2 ГБ для 32-разрядной программы, поэтому вполне вероятно, что оно достигнет этого предела. Вероятно, лучшим решением будет разработка вашего приложения в 64-битном режиме, тогда вы сможете выделить огромное количество (виртуальной) оперативной памяти.

Я читал о std::vector и std::deque. Я считаю, что std:: deque является моим решением этой проблемы, так как std::vector выделяет большой кусок последовательной памяти, как это делает malloc().

Нет, используя std::vector или же std::deque не обязательно решит вашу проблему, если это будет фрагментация или перераспределение (скорее всего). Они оба будут использовать new/malloc в их реализации для выделения памяти в любом случае, так что, если вы уже знаете границы своих распределений, вы могли бы также запросить всю сумму заранее, как вы делаете.

Есть ли другие решения для изучения или std:: deque - мое единственное решение?

  1. deque это не решение
  2. Анализируйте ваши требования к памяти, шаблоны доступа и уменьшите использование
  3. Если вы не можете использовать более 2 ГБ, переключитесь на 64-битную ОС

Это зависит от того, сколько у вас оперативной памяти. Вам нужно 5 * 70MB * 8 = 2800MB. Есть несколько случаев:

  • Если у вас есть гораздо больше, найти его не должно быть проблемой, даже в смежных блоках. Я полагаю, у вас не так много.
  • Если, с другой стороны, у вас не так много памяти, ни один контейнер не будет соответствовать вашим потребностям, и вы ничего не сможете сделать, кроме как добавить ОЗУ или модифицировать свою программу, чтобы использовать меньше ядер.
  • В промежуточном случае, т. Е. Ваша память не меньше этого, но не намного больше, переключение на другой контейнер может работать, но есть еще проблемы: имейте в виду, что вектор очень компактен, так как он непрерывен; любой вид связанного списка должен хранить указатели на следующие элементы, и эти указатели могут занимать значительное пространство, поэтому вам может понадобиться более 2800 МБ, хотя и не в смежных блоках. std::listс этой точки зрения было бы ужасно, потому что для этого нужен указатель на каждый элемент. Так что, если ваши векторы содержат несколько больших элементов, переключение на список приведет к небольшим накладным расходам из-за этих нескольких указателей, но если они содержат много небольших значений, список заставит вас тратить много места на хранить указатели. В этом смысле deque должен быть тем, что вам нужно, поскольку внутренне он обычно реализуется как группа массивов, поэтому вам не нужен указатель на каждый элемент.

В заключение: да, deque - это то, что вы ищете. Это потребует больше памяти, чем векторов, но только немного, и эта память не должна быть смежной, поэтому у вас не должно быть больше проблем фрагментации ОЗУ.

Другие вопросы по тегам