Сопоставленный файл не занимает память при чтении, но при записи - PullRequest
0 голосов
/ 07 июня 2018

Я наблюдал странное поведение, когда большой файл с отображенной памятью (2 ГБ) не берет реальную физическую память, когда я читаю из нее, но делает, когда я начинаю писать в нее.

int err = 0;

int fd = open("large_file", O_RDWR);
if (fd == -1) {
    return errno;
}

void *map = mmap(NULL, size, PROT_READ | PROT_WRITE, 
                 MAP_PRIVATE, fd, 0); 
if (map == MAP_FAILED) {
     err = errno;
     goto out;
}

for (unsigned int i = 0; i < 2 << 30; i += PAGE_SIZE) {
      volatile uint8_t val = 0xff;

      // val = ((volatile uint8_t *) map)[i]; /* Doesn't take actual memory */
      // ((volatile uint8_t *) map[i]) = val; /* Takes actual memory */
}

while (1)
    sleep(10);

out:
   if (fd != -1)
      close(fd);
   if (map != MAP_FAILED)
      munmap(map, size);
return err;

Это снимок экрана htop, когда я ЧИТАЙ из сопоставленного файла (см. "Check")

ЭтоСнимок экрана htop, когда я ЗАПИСИ в сопоставленный файл (посмотрите на "check"

Мой ноутбук в значительной степени бездействует, ничто иное не может взять физическую оперативную память, кроме моего процесса тестирования, поэтомувы можете видеть, что когда я записываю в сопоставленный файл, он фактически занимает 2 ГБ (копирование при записи), а при чтении - нет. RES-SHR также подходит для обоих моих случаев.

Я могуне объясните это .. ядро ​​отображает новую страницу независимо от того, является ли она чтением или записью в физическую ОЗУ. Если она отсутствует, она должна отображаться и занимать фактическую ОЗУ после исключения сбоя страницы. Отображенный файл не сопоставлен с другими процессами, поэтому он не используется совместно. Процесс тестирования является единственным и первым, который отображает файл в память.

РЕДАКТИРОВАТЬ: я добавил (volatile), чтобы компилятор не оптимизировал критический код.сть.Этот конкретный фрагмент ассемблерного кода является результатом чтения из отображенного в память файла:

mov    BYTE PTR [rbp-0xbd],0xff /* volatile uint8_t val = 0xff; */
mov    edx,DWORD PTR [rbp-0xbc] 
mov    rax,QWORD PTR [rbp-0xb0]
add    rax,rdx
movzx  eax,BYTE PTR [rax]     
mov    BYTE PTR [rbp-0xbd],al   /* val = ((volatile uint8_t *)map)[i]; */
add    DWORD PTR [rbp-0xbc],0x1000 /* i += PAGE_SIZE; */

Есть мысли?

1 Ответ

0 голосов
/ 07 июня 2018

Вероятно, ваш компилятор просто оптимизирует доступ для чтения.Это может быть сделано, поскольку вы никогда ничего с этим не делаете.Проще всего было бы изменить объявление val:

uint8_t volatile val = ... ;

, но вы также можете объявить map соответственно:

uint8_t volatile*map = mmap(NULL, size, PROT_READ | PROT_WRITE, 
             MAP_PRIVATE, fd, 0);

(Объявление искомого типа для map такжеПозволяет избежать отвратительного применения позже.)

...