В 64-битном процессе мне будет отказано в моем запросе mmap/malloc?

Адресное пространство для 64-разрядной адресации абсолютно огромно. У меня есть программа, которая будет mmap несколько блоков памяти, каждая из которых составляет порядка 100 - 500 МБ. Я неизбежно буду переназначать несколько раз, что может привести к некоторой фрагментации доступного непрерывного пространства.

Какая бы фрагментация пространства не происходила, она, безусловно, будет крайне мала, касающейся доступного адресного пространства.

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

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

Mac OS/Linux.

Ответы

Ответ 1

Помните, что размер адресного пространства для "64-битных операционных систем" не обязательно покрывает полный 64-битный диапазон.

В x64 (64 бит x86, ака 'AMD64'), например, фактический диапазон доступных виртуальных адресов "только" 2x128TB, т.е. 48 бит в двух непересекающихся 47-битных фрагментах. В некоторых системах SPARC это 2x2TB или 2x8TB (41/44 бит). Это связано с тем, как MMU работает на этих платформах.

В дополнение к этим архитектурным ограничениям, то, как операционная система определяет ваши адресные пространства, также играет здесь роль. Например, 64-битная Windows на x64 ограничивает размер виртуального адреса (даже 64-битного) приложения до 8 ТБ (каждое ядро ​​и пользовательская сторона 1).

В системах UN * X (включая Linux, MacOSX и * BSD) существует RLIMIT_AS, который можно запросить через getrlimit(), и - в пределах системных ограничений - отрегулируйте через setrlimit. Для этого используется команда ulimit. Они возвращают/устанавливают верхнюю границу, т.е. Допустимое общее виртуальное адресное пространство, включая все сопоставления, которые может создать процесс (через mmap() или бэкенд malloc, sbrk()). Но общий размер адресного пространства отличается от максимального размера одного отображения...

Учитывая это, не так сложно исчерпать виртуальное адресное пространство даже на 64-битной Linux; просто попробуйте, для теста, mmap() тот же 500GB файл, скажем, в двести раз. В конце концов mmap не удастся.

Короче:

  • mmap(), безусловно, будет терпеть неудачу, если вы вышли из виртуального адресного пространства. Что, как ни удивительно, достижимо на многих "64-битных" архитектурах, просто потому, что виртуальные адреса могут иметь менее 64 значащих бит. Точная отсечка зависит от вашего процессора и вашей операционной системы, а верхняя граница может быть запрошена через getrlimit(RLIMIT_AS) или установлена ​​через setrlimit(RLIMIT_AS).
  • Фрагментация адресного пространства может происходить на 64-битной часто при использовании mmap()/munmap() в разных порядках и блоках разного размера. Это в конечном итоге ограничит максимальный размер, который вы сможете отобразить в виде одного фрагмента. Предсказание того, когда это произойдет, сложно, так как оно зависит от вашей истории сопоставления и алгоритма распределения виртуального адресного пространства операционных систем. Если ASLR (рандомизация размещения адресного пространства) выполняется ОС, это может быть непредсказуемо подробно, а не точно воспроизводимым.
  • malloc() также завершится не позднее достижения полного предела VA в системах (например, Linux), где overcommit позволяет "запрашивать" больше памяти, чем в системе (физическая + своп).
  • В машинах/операционных системах, где не включен overcommit, обе версии malloc() и mmap() с MAP_ANON и/или MAP_PRIVATE будут терпеть неудачу, если физический + swap будет исчерпан, потому что для этих типов сопоставлений требуется резервное хранилище на фактическая память или своп.

Небольшое техническое обновление: Как и x86 и sparc, упомянутые выше, новый ARMv8 (64-битный ARM, называемый "AArch64" в Linux) MMU также имеет "разделенное" адресное пространство/адресное пространство - из 64 бит в адрес, всего 40. Linux дает 39 бит для пользователя, виртуальные адреса 0 ... и далее, 39 бит для ядра, виртуальные адреса ... 0xFFFFFFFF.FFFFFFFF, поэтому предел составляет 512 ГБ (минус то, что используется в то время, когда приложение пытается использовать mmap).
См. комментарии здесь (из серии исправлений ядра ядра AArch64).

Ответ 2

mmap и malloc могут выйти из строя из-за нехватки физической памяти (RAM + swap). В общем, стандарт Unix говорит о диапазонах адресов, которые "разрешены для адресного пространства процесса". Кроме того,

Если функция объявлена ​​для возврата код ошибки в случае трудности, вы должны проверить этот код, да, хотя проверки втрое размер вашего кода и производить боли в печатных пальцах, потому что, если ты считаешь, что он не может случиться со мной ", боги обязательно будут наказывай тебя за свое высокомерие.

(Spencer)

Ответ 3

Просто проверьте список ошибок в man mmap.

Ответ 4

Ну, библиотека OS/C может решить, достаточно ли памяти или нет. Вам действительно не нужно знать, как он это решает (очевидно, он зависит от ОС, возможно, даже настраивается), но возможно, что в какой-то момент ОС говорит "не больше".

Возможные причины отказа в распределении памяти:

  • Linux будет overcommit память, но это настраивается. В зависимости от того, как он настроен, вы можете получить ENOMEM, как только вы превысите RAM + Swap.
  • Если ограничения памяти установлены с помощью ulimit, вы можете получить ENOMEM еще раньше