2012-02-03 2 views
6

Я пытаюсь использовать mmap() для управления виртуальной памятью. Я хочу зарезервировать и зафиксировать область памяти. Я тестировал (а) этот код:Почему вызов 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 ГБ оперативной памяти. Может ли кто-нибудь рассказать мне об этом?

+1

прочитал о перекомпоновке памяти – PlasmaHH

+0

Код, который вы публикуете, ничего не совершает. Попробуйте пройти через эти области памяти. – Mat

ответ

11

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

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

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

+0

Должно ли это выглядеть так? 'pMemory = (char *) mmap (NULL, maxCapacity, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); mlock (pMemory, maxCapacity) 'Я думаю, что память, используемая в mlock(), не является памятью, зарезервированной с помощью mmap(). – antpetr89

+0

Я попытался зарезервировать 1 ГБ и передать их таким образом. Но mlock() возвращен -1. – antpetr89

+1

@ user1173593: После этого проверьте значение 'errno'. Это может быть «EPERM», указывая, что ваш предел ресурсов слишком низок (вы можете установить его с помощью 'ulimit -l', но, вероятно, есть и жесткий предел) или, возможно,« ENOMEM », что указывает на нехватку памяти , или другие ошибки, задокументированные в man-странице. –

0

Вы должны сначала проверить результат 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 */ 
} 
1

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

0

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

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

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

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