Почему COW mmap не работает с ENOMEM для (разреженных) файлов размером более 4 ГБ? - PullRequest
4 голосов
/ 01 сентября 2010

Это происходит в ядре Linux 2.6.26-2-amd64 при попытке отобразить файл размером 5 ГБ с семантикой копирования при записи (PROT_READ | PROT_WRITE и MAP_PRIVATE). Сопоставление файлов размером менее 4 ГБ или использование только PROT_READ работает нормально. Это не проблема мягкого ограничения ресурсов, о которой сообщалось в this question ; размер виртуального лимита не ограничен.

Вот код, который воспроизводит проблему (фактический код является частью Boost.Interprocess ).

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>

#include <fcntl.h>
#include <unistd.h>

main()
{
        struct stat b;
        void *base;
        int fd = open("foo.bin", O_RDWR);

        fstat(fd, &b);
        base = mmap(0, b.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
        if (base == MAP_FAILED) {
                perror("mmap");
                return 1;
        }
        return 0;
}

и вот что происходит:

dd if=/dev/zero of=foo.bin bs=1M seek=5000 count=1
./test-mmap
mmap: Cannot allocate memory

Вот соответствующий вывод strace (недавно скомпилированный 4.5.20), как указано в nos.

open("foo.bin", O_RDWR)                 = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=5243928576, ...}) = 0
mmap(NULL, 5243928576, PROT_READ|PROT_WRITE, MAP_PRIVATE, 3, 0) = -1 ENOMEM (Cannot allocate memory)
dup(2)                                  = 4
[...]
write(4, "mmap: Cannot allocate memory\n", 29mmap: Cannot allocate memory
) = 29

Ответы [ 2 ]

5 голосов
/ 01 сентября 2010

Попробуйте передать MAP_NORESERVE в поле flags, например:

mmap(NULL, b.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_NORESERVE, fd, 0);

Вероятно, комбинация вашей подкачки и физической памяти меньше, чем запрошенные 5 ГБ.

В качестве альтернативы вы можете сделать это для целей тестирования, если это работает, вы можете внести изменения в код выше:

# echo 0 > /proc/sys/vm/overcommit_memory

Ниже приведены соответствующие выдержки из страниц справочника.

ММАП (2):

   MAP_NORESERVE
          Do  not reserve swap space for this mapping.  When swap space is
          reserved, one has the guarantee that it is  possible  to  modify
          the  mapping.   When  swap  space  is not reserved one might get
          SIGSEGV upon a write if no physical memory  is  available.   See
          also  the  discussion of the file /proc/sys/vm/overcommit_memory
          in proc(5).  In kernels before 2.6, this flag  only  had  effect
          for private writable mappings.

прок (5):

   /proc/sys/vm/overcommit_memory
          This file contains the kernel virtual  memory  accounting  mode.
          Values are:

                 0: heuristic overcommit (this is the default)
                 1: always overcommit, never check
                 2: always check, never overcommit

          In  mode 0, calls of mmap(2) with MAP_NORESERVE are not checked,
          and the default check is very weak, leading to the risk of  get‐
          ting a process "OOM-killed".  Under Linux 2.4 any non-zero value
          implies mode 1.  In mode 2  (available  since  Linux  2.6),  the
          total  virtual  address  space on the system is limited to (SS +
          RAM*(r/100)), where SS is the size of the swap space, and RAM is
          the  size  of  the physical memory, and r is the contents of the
          file /proc/sys/vm/overcommit_ratio.
2 голосов
/ 01 сентября 2010

Цитирование вашей памяти, размера подкачки и настроек overcommit из вашего комментария:

MemTotal: 4063428 kB SwapTotal: 514072 kB
$ cat /proc/sys/vm/overcommit_memory
0
$ cat /proc/sys/vm/overcommit_ratio 
50

Если для overcommit_memory установлено значение 0 («эвристическое превышение»), вы не можете создать частное сопоставляемое для записи отображение, которое больше текущей свободной памяти и общего объема подкачки - ясно, поскольку у вас есть только 4,5 ГБ памяти + подкачка , это никогда не может быть правдой.

Вы можете использовать MAP_NORESERVE (как подсказывает Мэтт Джойнер ), если вы уверены, что вы никогда не испачкаете (напишите) больше страниц в сопоставлении, чем у вас есть свободная память и обменять на; или значительно увеличить размер пространства подкачки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...