Я работал с большими редкими файлами на openSUSE 11.2 x86_64. Когда я пробую к mmap () редкий файл на 1 ТБ, он перестал работать с ENOMEM. Я думал бы, что 64 бита адресного пространства будут соответствовать для отображения в терабайте, но это кажется нет. Экспериментируя далее, файл на 1 ГБ хорошо работает, но файл на 2 ГБ (и что-либо большее) сбои. Я предполагаю, что могла бы быть установка где-нибудь для тонкой настройки, но обширный поиск ничего не поднимает.
Вот некоторый пример кода, который показывает проблему - какие-либо подсказки?
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
char * filename = argv[1];
int fd;
off_t size = 1UL << 40; // 30 == 1GB, 40 == 1TB
fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0666);
ftruncate(fd, size);
printf("Created %ld byte sparse file\n", size);
char * buffer = (char *)mmap(NULL, (size_t)size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if ( buffer == MAP_FAILED ) {
perror("mmap");
exit(1);
}
printf("Done mmap - returned 0x0%lx\n", (unsigned long)buffer);
strcpy( buffer, "cafebabe" );
printf("Wrote to start\n");
strcpy( buffer + (size - 9), "deadbeef" );
printf("Wrote to end\n");
if ( munmap(buffer, (size_t)size) < 0 ) {
perror("munmap");
exit(1);
}
close(fd);
return 0;
}
Проблема заключалась в том, что предел виртуальной памяти для каждого процесса был установлен только 1,7 ГБ. ulimit -v 1610612736
установил для него значение 1,5 ТБ, и мой вызов mmap () завершился успешно. Спасибо, bmargulies , за подсказку попробовать ulimit -a!
Существует ли какая-то квота на пользователя, ограничивающая объем памяти, доступной пользовательскому процессу?
Я думаю, что ядро испытывает трудности с выделением памяти, которая ему нужна для поддержания этого отображения памяти. Я не знаю, как хранятся выгруженные страницы в ядре Linux (и я предполагаю, что большая часть файла будет находиться в выгруженном состоянии большую часть времени), но в итоге может потребоваться запись для каждой страницы памяти, которую занимает файл в таблице. Поскольку этот файл может быть отображен более чем одним процессом, ядро должно следить за отображением с точки зрения процесса, который будет отображаться на другую точку зрения, которая будет отображаться на вторичное хранилище (и включать поля для устройства и местоположения).
Это поместится в ваше адресуемое пространство, но может не поместиться (по крайней мере, смежно) в физической памяти.
Если кто-то знает больше о том, как Linux делает это, мне было бы интересно узнать об этом.