Почему вызов mmap () с большим размером не дает сбоя? - PullRequest
6 голосов
/ 03 февраля 2012

Я пытаюсь использовать mmap() для управления виртуальной памятью. Я хочу зарезервировать и зафиксировать область памяти. Я проверил этот код:

const unsigned long gygabyte = 1024 * 1024 * 1024;
const unsigned long gygabyteCount = 2;
const unsigned long maxCapacity = gygabyteCount * gygabyte;

int main()
{
    char* pMemory;

    pMemory = (char*)mmap(NULL, maxCapacity, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    if ( mprotect(pMemory, maxCapacity, PROT_READ | PROT_WRITE) != 0 )
    {
        cout << "Memory Allocation has failed" << endl;
    }
    usleep(-1);

    return 0;
}

Я запустил несколько копий моей программы (скажем, 6) из терминала. Я никогда не видел "Распределение памяти не удалось" ни в одном. Я работаю на 64-битной Ubuntu с 4 ГБ оперативной памяти. Кто-нибудь может сказать мне что-нибудь об этом?

Ответы [ 4 ]

11 голосов
/ 03 февраля 2012

mmap резервирует область виртуального адресного пространства процесса, но не сразу выделяет для него физическую память.Поэтому на 64-битной платформе вы можете зарезервировать огромное количество без сбоев (хотя вам все равно нужно проверять на наличие сбоев; ваш пример кода этого не делает).Физические страницы ОЗУ выделяются позже при обращении к памяти.

mprotect просто изменяет доступ на чтение / запись зарезервированной памяти;это также не сделает его резидентным в RAM.Вы получите тот же эффект, передав PROT_READ | PROT_WRITE вместо PROT_NONE в mmap и удалив вызов в mprotect.

Если вам нужно, чтобы память была резидентной в оперативной памяти,используйте для этого mlock.Он потерпит неудачу, если не будет достаточно оперативной памяти.На многих платформах Linux (включая Ubuntu) существует ограничение ресурса (RLIMIT_MEMLOCK), которое ограничивает объем памяти, который может заблокировать любой процесс;Вы можете настроить это с помощью ulimit -l.

1 голос
/ 03 февраля 2012

mmap полезен для подготовки отображения памяти, которую вы запрашиваете, но не выделяет ее для вашей программы.Ядро заботится о выделении памяти при обращении к ней, поэтому mmap -ing 8 ГБ возможно для 4 ГБ памяти, если вы не обращаетесь к этим 8 ГБ одновременно.

0 голосов
/ 03 февраля 2012

Во-первых, вы должны сказать Linux, что хотите, чтобы он выполнял учет коммитов:

echo "2" > /proc/sys/vm/overcommit_memory

В противном случае он сохраняет устаревшее значение по умолчанию (с тех пор, как Linux была игрушечной ОС), позволяющее неограниченное количество перегрузок и ужасное падение ваших приложений, когда им не хватает физической памяти.

Также, как уже говорили другие, вам нужно проверить возвращаемое значение mmap против MAP_FAILED, и нет необходимости использовать mprotect. Для начала просто передайте правильные значения от PROT_* до mmap.

0 голосов
/ 03 февраля 2012

Сначала вы должны проверить результат mmap.Если он возвращает MAP_FAILED, это означает, что распределение не выполнено.Ядро на самом деле не выделит столько памяти сразу, а скорее отобразит физическое пространство или пространство подкачки по требованию, когда вы получите доступ к соответствующим областям этого блока.

В вашем конкретном случае вам не нуженОтдельный вызов mprotect, поскольку эти флаги для всего региона можно выполнить во время вызова mmap:

pMemory = mmap(NULL, maxCapacity,
    PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

if (pMemory == MAP_FAILED) {
    /* allocation failed */
}
...