Подтвердить что ты не робот

Mmap не работает, если длина превышает 4 ГБ

(Правильный код находится в "Обновить 5" )

Я попытался отобразить диапазон памяти от 0x100000000 до 0x200000000 в этом примере кода C:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/mman.h>

int main(void)
{ 
    uint64_t* rr_addr = 0;
    uint64_t i = 17179869184;

    printf("\nsizeof(size_t): %llu\n", sizeof(size_t));

    printf("(uint64_t)0x100000000: %llx\n", (uint64_t)0x100000000);
    printf("1L << 33: %llx\n", 1L << 33);
    rr_addr = mmap((void*)i, (1UL << 33), PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
    printf("rr_addr: %p, %llu \n", rr_addr, rr_addr);
    if (rr_addr == MAP_FAILED) {
        perror("mmap error");
    }

    return 0;
}

В разных системах (Linux, gcc) я получаю разные результаты:

Результат 1:

sizeof(size_t): 8
(uint64_t)0x100000000: 100000000
1L << 33: 200000000
rr_addr: 0xffffffffffffffff, 18446744073709551615 
mmap error: Cannot allocate memory

Информация о системе (Fedora 14):

Linux localhost.localdomain 2.6.35.10-74.fc14.x86_64 #1 SMP Thu Dec 23 16:04:50 UTC 2010 x86_64 x86_64 x86_64 GNU/Linux

gcc (GCC) 4.5.1 20100924 (Red Hat 4.5.1-4)

glibc: 2.12.90-21

Результат 2:

sizeof(size_t): 8
(uint64_t)0x100000000: 100000000
1L << 33: 200000000
rr_addr: 0x400000000, 17179869184 

Информация о системе (Fedora 12):

Linux wiles 2.6.32.13 #2 SMP Fri Sep 10 01:29:43 HKT 2010 x86_64 x86_64 x86_64 GNU/Linux

gcc (GCC) 4.4.4 20100630 (Red Hat 4.4.4-10)

glibc verison: 2.11.2-1

Я ожидаю "Результат 2". Возможно, что-то не так с моим кодом.

Пожалуйста, помогите мне.

Обновление 1: errno распечатывается, если mmap не работает.

Обновление 3: после изменения вызова mmap на следующие строки:

char *cmd[20]; 

sprintf(cmd, "pmap -x %i", getpid()); 
printf("%s\n", cmd);
system(cmd);

rr_addr = mmap((void*)i, (1UL << 33), PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);

printf("%s\n", cmd);
system(cmd);

Результат:

sizeof(size_t): 8
(uint64_t)0x100000000: 100000000
1L << 33: 200000000
pmap -x 5618
5618:   ./test
Address           Kbytes     RSS   Dirty Mode   Mapping
0000000000400000       4       4       0 r-x--  test
0000000000600000       4       4       4 rw---  test
00007f1cc941e000    1640     280       0 r-x--  libc-2.12.90.so
00007f1cc95b8000    2044       0       0 -----  libc-2.12.90.so
00007f1cc97b7000      16      16      16 r----  libc-2.12.90.so
00007f1cc97bb000       4       4       4 rw---  libc-2.12.90.so
00007f1cc97bc000      24      16      16 rw---    [ anon ]
00007f1cc97c2000     132     108       0 r-x--  ld-2.12.90.so
00007f1cc99c6000      12      12      12 rw---    [ anon ]
00007f1cc99e0000       8       8       8 rw---    [ anon ]
00007f1cc99e2000       4       4       4 r----  ld-2.12.90.so
00007f1cc99e3000       4       4       4 rw---  ld-2.12.90.so
00007f1cc99e4000       4       4       4 rw---    [ anon ]
00007fffa0da8000     132       8       8 rw---    [ stack ]
00007fffa0dff000       4       4       0 r-x--    [ anon ]
ffffffffff600000       4       0       0 r-x--    [ anon ]
----------------  ------  ------  ------
total kB            4040     476      80
pmap -x 5618
5618:   ./test
Address           Kbytes     RSS   Dirty Mode   Mapping
0000000000400000       4       4       0 r-x--  test
0000000000600000       4       4       4 rw---  test
00007f1cc941e000    1640     280       0 r-x--  libc-2.12.90.so
00007f1cc95b8000    2044       0       0 -----  libc-2.12.90.so
00007f1cc97b7000      16      16      16 r----  libc-2.12.90.so
00007f1cc97bb000       4       4       4 rw---  libc-2.12.90.so
00007f1cc97bc000      24      16      16 rw---    [ anon ]
00007f1cc97c2000     132     108       0 r-x--  ld-2.12.90.so
00007f1cc99c6000      12      12      12 rw---    [ anon ]
00007f1cc99e0000       8       8       8 rw---    [ anon ]
00007f1cc99e2000       4       4       4 r----  ld-2.12.90.so
00007f1cc99e3000       4       4       4 rw---  ld-2.12.90.so
00007f1cc99e4000       4       4       4 rw---    [ anon ]
00007fffa0da8000     132       8       8 rw---    [ stack ]
00007fffa0dff000       4       4       0 r-x--    [ anon ]
ffffffffff600000       4       0       0 r-x--    [ anon ]
----------------  ------  ------  ------
total kB            4040     476      80
rr_addr: 0xffffffffffffffff, 18446744073709551615 
mmap error: Cannot allocate memory

Обновить 4: добавить "system (" ulimit -m -v "); перед вызовом mmap: Выход ulimit:

max memory size         (kbytes, -m) unlimited
virtual memory          (kbytes, -v) unlimited

Другой вывод такой же, как "Обновление 3" (все еще не удается), кроме pid.

Обновление 5: обновленный код, который работает в обеих системах:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/mman.h>

int main(void)
{ 
    uint64_t* rr_addr = 0;
    uint64_t i = 17179869184;
    uint64_t len = 0;

    char cmd[20]; 

    printf("\nsizeof(size_t): %llu\n", sizeof(size_t));

    len = (1UL << 32);
    printf("len: %llx\n", len);

    snprintf(cmd, sizeof cmd, "pmap -x %i", getpid()); 
    printf("%s\n", cmd);
    system(cmd);

    system("ulimit -m -v");

    rr_addr = mmap((void*)i, len, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE|MAP_NORESERVE, -1, 0);

    printf("%s\n", cmd);
    system(cmd);

    printf("rr_addr: %p, %llu \n", rr_addr, rr_addr);
    if (rr_addr == MAP_FAILED) {
        perror("mmap error");
    }

    return 0;
}

Правильный ответ задается @caf: добавление флага MAP_NORESERVE в mmap решает эту проблему. Подробная информация о причине находится в ответе кафе. Большое спасибо кафе, и все это дает вам любезную помощь!

4b9b3361

Ответ 1

Если у вас на самом деле не установлено более 8 Гбайт свопинга, то скорее всего это приведет к сбою.

Вы можете добавить флаг MAP_NORESERVE в mmap(), чтобы он не резервировал какое-либо пространство подкачки для отображения вверх.

Ответ 2

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

cat /proc/sys/vm/overcommit_memory
cat /proc/sys/vm/overcommit_ratio

Если overcommit_memory не 0, то каждое распределение адресного пространства должно поддерживаться физической памятью (RAM + swap space), если overcommit_memory - 0, тогда память является чрезмерной, то есть ядро ​​с радостью передаст адресное пространство, но память будет выделена только в том случае, если данные записываются в выделенное адресное пространство. И тогда память не выделяется для полного зарезервированного адресного пространства, но только для тех страниц, которые были затронуты. Это похоже на бронирование авиабилета: авиакомпании обычно продают больше билетов, чем есть места на рейсе, ожидая, что не все забронированные пассажиры действительно появятся. Теперь вы можете задаться вопросом, что произойдет, если все программы воспользуются полным пространством... Ну, тогда какая-то неприятная вещь начнется: "Linux Out Of Memory Killer" нанесет ущерб вашей системе и, скорее всего, уничтожит те процессы, которые вам нужны больше всего, из-за это тайная эвристика.

overcommit_ratio сообщает ядру

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

  • в режиме без перекомпоновки, сколько резервной памяти сохранить

Итак, возможно, режим overcommit просто отличается между системами.

Ответ 3

Просто запустил ваш код на Fedora 13, и он производит результат 2.

Проверить errno, когда mmap() возвращает MAP_FAILED (-1). Вы также можете придерживаться следующей строки до и после вызова mmap, чтобы узнать, есть ли у вас пространство в виртуальном адресном пространстве процесса для область 4 ГБ:

system("pmap -x $$");

Update: Вышеописанное на самом деле печатает карту дочернего процесса. Правильный код:

char buf[0x100];
snprintf(buf, sizeof buf, "pmap -x %u", (unsigned)getpid());
system(buf);

Ответ 4

Поскольку вы пытаетесь сопоставить определенный адрес, он будет зависеть от текущего макета памяти для вашего процесса, когда вы вызываете mmap. Стратегия, по которой выполняется запрос, зависит от системы, на странице руководства Linux говорится что-то вроде "подсказки".

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

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

Ответ 5

Возможно, вы сталкиваетесь с ограничениями ресурсов? Попробуйте добавить system("ulimit -m -v");, чтобы распечатать объем памяти и адресное пространство, которое может быть выделено.

РЕДАКТИРОВАТЬ. Ну, у меня нет идей. Сожалею. После очистки ошибок и предупреждений в коде у меня есть этот источник:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/mman.h>

int main(void)
{
    uint64_t* rr_addr = 0;
    uint64_t i = 17179869184;

    printf("\nsizeof(size_t): %lu\n", sizeof(size_t));

    printf("(uint64_t)0x100000000: %lx\n", (uint64_t)0x100000000);
    printf("1L << 33: %lx\n", 1L << 33);

    char cmd[20];

    sprintf(cmd, "pmap -x %i", getpid());
    printf("%s\n", cmd);
    system(cmd);

    rr_addr = mmap((void*)i, (1UL << 33), PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);

    printf("%s\n", cmd);
    system(cmd);


    printf("rr_addr: %p, %lu \n", rr_addr, rr_addr);
    if (rr_addr == MAP_FAILED) {
        perror("mmap error");
    }

    return 0;
}

и этот вывод:

sizeof(size_t): 8
(uint64_t)0x100000000: 100000000
1L << 33: 200000000
pmap -x 23819
23819:   ./zhiqiang
Address           Kbytes     RSS   Dirty Mode   Mapping
0000000000400000       0       4       0 r-x--  zhiqiang
0000000000600000       0       4       4 r----  zhiqiang
0000000000601000       0       4       4 rw---  zhiqiang
00007f37b3c27000       0     260       0 r-x--  libc-2.12.1.so
00007f37b3da1000       0       0       0 -----  libc-2.12.1.so
00007f37b3fa0000       0      16      16 r----  libc-2.12.1.so
00007f37b3fa4000       0       4       4 rw---  libc-2.12.1.so
00007f37b3fa5000       0      12      12 rw---    [ anon ]
00007f37b3faa000       0     108       0 r-x--  ld-2.12.1.so
00007f37b41aa000       0      12      12 rw---    [ anon ]
00007f37b41c7000       0      12      12 rw---    [ anon ]
00007f37b41ca000       0       4       4 r----  ld-2.12.1.so
00007f37b41cb000       0       4       4 rw---  ld-2.12.1.so
00007f37b41cc000       0       4       4 rw---    [ anon ]
00007fff70cf8000       0      12      12 rw---    [ stack ]
00007fff70dff000       0       4       0 r-x--    [ anon ]
ffffffffff600000       0       0       0 r-x--    [ anon ]
----------------  ------  ------  ------
total kB            3912     464      88
pmap -x 23819
23819:   ./zhiqiang
Address           Kbytes     RSS   Dirty Mode   Mapping
0000000000400000       0       4       0 r-x--  zhiqiang
0000000000600000       0       4       4 r----  zhiqiang
0000000000601000       0       4       4 rw---  zhiqiang   
0000000400000000       0       0       0 rw---    [ anon ]
00007f37b3c27000       0     260       0 r-x--  libc-2.12.1.so
00007f37b3da1000       0       0       0 -----  libc-2.12.1.so
00007f37b3fa0000       0      16      16 r----  libc-2.12.1.so
00007f37b3fa4000       0       4       4 rw---  libc-2.12.1.so
00007f37b3fa5000       0      12      12 rw---    [ anon ]
00007f37b3faa000       0     108       0 r-x--  ld-2.12.1.so
00007f37b41aa000       0      12      12 rw---    [ anon ]
00007f37b41c7000       0      12      12 rw---    [ anon ]
00007f37b41ca000       0       4       4 r----  ld-2.12.1.so
00007f37b41cb000       0       4       4 rw---  ld-2.12.1.so
00007f37b41cc000       0       4       4 rw---    [ anon ]
00007fff70cf8000       0      12      12 rw---    [ stack ]
00007fff70dff000       0       4       0 r-x--    [ anon ]
ffffffffff600000       0       0       0 r-x--    [ anon ]
----------------  ------  ------  ------
total kB         8392520     464      88
rr_addr: 0x400000000, 17179869184

И подробности моей системы:

Linux haig 2.6.35-24-generic #42-Ubuntu SMP Thu Dec 2 02:41:37 UTC 2010 x86_64 GNU/Linux
gcc version 4.4.5 (Ubuntu/Linaro 4.4.4-14ubuntu5)
GNU C Library (Ubuntu EGLIBC 2.12.1-0ubuntu10.1) stable release version 2.12.1, by Roland McGrath et al.