Сколько памяти вы должны быть в состоянии выделить?

StackOverflow https://stackoverflow.com/questions/1034045

Вопрос

Предыстория:Я пишу программу на C ++, работающую с большими объемами геоданных, и хочу загружать большие куски для обработки за один раз.Я вынужден работать с приложением, скомпилированным для 32-разрядных машин.Машина, на которой я тестирую, работает под управлением 64-разрядной ОС (Windows 7) и имеет 6 гигабайт оперативной памяти.Используя MS VS 2008.

У меня есть следующий код:

byte* pTempBuffer2[3];
try
{
    //size_t nBufSize = nBandBytes*m_nBandCount;
    pTempBuffer2[0] = new byte[nBandBytes];
    pTempBuffer2[1] = new byte[nBandBytes];
    pTempBuffer2[2] = new byte[nBandBytes];
}
catch (std::bad_alloc)
{
    // If we didn't get the memory just don't buffer and we will get data one
    // piece at a time.
    return;
}

Я надеялся, что смогу выделять память до тех пор, пока приложение не достигнет предела в 4 гигабайта для 32-разрядной адресации.Однако, когда nBandBytes равен 466 560 000, new выдает std::bad_alloc со второй попытки.На данном этапе значение рабочего набора (памяти) для процесса равно 665 232 К, так что, похоже, я не смогу выделить даже гигабайт памяти.

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

Какой объем памяти вы должны иметь возможность выделить под 64-разрядную ОС с 32-разрядным приложением?

Это было полезно?

Решение

Столько, сколько операционная система хочет вам дать.По умолчанию Windows предоставляет 32-разрядному процессу 2 ГБ адресного пространства.И это разделяется на несколько частей.Одна область отведена для стека, другие - для каждого загружаемого исполняемого файла и библиотеки dll.Все, что осталось, может быть распределено динамически, но нет никакой гарантии, что это будет один большой непрерывный фрагмент.Это может быть несколько небольших блоков по паре сотен МБ каждый.

Если вы скомпилируете с флагом LargeAddressAware, 64-разрядная Windows позволит вам использовать все адресное пространство объемом 4 ГБ, что должно немного помочь, но в целом,

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

Другие советы

в 32-битной Windows нормальный процесс может занять максимум 2 ГБ, но с / 3GB может достигать 3 ГБ (для Windows 2003).

но в вашем случае я думаю, что вы выделяете непрерывную память, и поэтому произошло исключение.

Вы можете выделить столько памяти, сколько позволит ваш файл подкачки - даже без ключа / 3GB вы можете выделить 4 ГБ памяти без особых затруднений.

Прочитайте эта статья для хорошего обзора того, как думать о физической памяти, виртуальной памяти и адресном пространстве (все три - разные вещи). Короче говоря, у вас ровно столько физической памяти, сколько у вас ОЗУ, но ваше приложение действительно вообще не взаимодействует с этой физической памятью - это просто удобное место для хранения данных в вашей виртуальной памяти. Ваша виртуальная память ограничена размером вашего файла подкачки, а объем, который может использовать ваше приложение, ограничен тем, как много других приложений используют (хотя вы можете выделить больше, если вы на самом деле не используете его). Ваше адресное пространство в 32-битном мире составляет 4 ГБ. Из них 2 ГБ выделяются ядру (или 1 ГБ, если вы используете ключ / 3BG). Из оставшихся 2 ГБ некоторые будут использованы вашим стеком, некоторые - программой, которую вы в данный момент используете (и всеми библиотеками и т. Д.). Это будет фрагментировано, и вы только сможете получить столько смежного пространства - это то, где ваше распределение не удается. Но так как это адресное пространство является просто удобным способом доступа к виртуальной памяти, которую вы выделили для вас, можно выделить гораздо больше памяти и по несколько раз помещать ее в свое адресное пространство.

У Реймонда Чена есть пример того, как выделить 4 ГБ памяти и отобразить ее часть в часть вашего адресного пространства.

В 32-разрядных Windows максимальный объем памяти составляет 16 ТБ и 256 ТБ в 64-разрядных Windows.

А если вам действительно интересно, как работает управление памятью в Windows, прочитайте эта статья .

Вы должны иметь возможность выделить около 2 ГБ на процесс. В этой статье (PDF) объясняется детали. Однако вы, вероятно, не сможете получить один непрерывный блок, даже близкий к такому большому.

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

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

Системные интерфейсы VMMap отлично подходит для исследования фрагментации виртуального адресного пространства, которая, вероятно, ограничивает объем непрерывной памяти, который вы можете выделить.Я рекомендую настроить его на отображение свободного места, затем отсортировать по размеру, чтобы найти самые большие свободные области, затем отсортировать по адресу, чтобы увидеть, что разделяет самые большие свободные области (возможно, перебазированные библиотеки DLL, области общей памяти или другие кучи).

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

Настройка LARGE_ADDRESS_AWARE=YES (как предложил jalf) хорош, если библиотеки, от которых зависит ваше приложение, совместимы с ним.Если вы сделаете это, вам следует протестировать свой код с помощью AllocationPreference раздел реестра, установленный для включения распределения виртуальных адресов по принципу "сверху вниз".

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top