Фрагментация в 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 - мое единственное решение?
deque
это не решение- Анализируйте ваши требования к памяти, шаблоны доступа и уменьшите использование
- Если вы не можете использовать более 2 ГБ, переключитесь на 64-битную ОС
Это зависит от того, сколько у вас оперативной памяти. Вам нужно 5 * 70MB * 8 = 2800MB. Есть несколько случаев:
- Если у вас есть гораздо больше, найти его не должно быть проблемой, даже в смежных блоках. Я полагаю, у вас не так много.
- Если, с другой стороны, у вас не так много памяти, ни один контейнер не будет соответствовать вашим потребностям, и вы ничего не сможете сделать, кроме как добавить ОЗУ или модифицировать свою программу, чтобы использовать меньше ядер.
- В промежуточном случае, т. Е. Ваша память не меньше этого, но не намного больше, переключение на другой контейнер может работать, но есть еще проблемы: имейте в виду, что вектор очень компактен, так как он непрерывен; любой вид связанного списка должен хранить указатели на следующие элементы, и эти указатели могут занимать значительное пространство, поэтому вам может понадобиться более 2800 МБ, хотя и не в смежных блоках.
std::list
с этой точки зрения было бы ужасно, потому что для этого нужен указатель на каждый элемент. Так что, если ваши векторы содержат несколько больших элементов, переключение на список приведет к небольшим накладным расходам из-за этих нескольких указателей, но если они содержат много небольших значений, список заставит вас тратить много места на хранить указатели. В этом смысле deque должен быть тем, что вам нужно, поскольку внутренне он обычно реализуется как группа массивов, поэтому вам не нужен указатель на каждый элемент.
В заключение: да, deque - это то, что вы ищете. Это потребует больше памяти, чем векторов, но только немного, и эта память не должна быть смежной, поэтому у вас не должно быть больше проблем фрагментации ОЗУ.