为什么mmap()在1TB稀疏文件上使用ENOMEM失败?

时间:2010-05-26 03:31:47

标签: c linux mmap

我一直在使用openSUSE 11.2 x86_64上的大型稀疏文件。当我尝试mmap()1TB稀疏文件时,它会因ENOMEM而失败。我原以为64位地址空间足以映射到太字节,但似乎没有。进一步尝试,1GB文件工作正常,但2GB文件(和更大的文件)失败。我猜测可能有某个地方可以调整,但广泛的搜索没有任何结果。

以下是一些显示问题的示例代码 - 任何线索?

#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;
}

3 个答案:

答案 0 :(得分:12)

问题在于每进程虚拟内存限制仅设置为1.7GB。 ulimit -v 1610612736将其设置为1.5TB并且我的mmap()调用成功。谢谢,bmargulies,提示尝试ulimit -a!

答案 1 :(得分:2)

是否存在某种每用户配额,限制了用户进程可用的内存量?

答案 2 :(得分:1)

我的猜测是内核难以分配内存,因此需要跟上这个内存映射。我不知道如何在Linux内核中保持换出的页面(我假设大部分文件大部分时间都处于交换状态),但最终可能需要为每个页面输入一个条目文件占用表的内存。由于此文件可能由多个进程进行mmap,因此内核必须跟上进程视角的映射,该映射将映射到另一个视点,该视图将映射到辅助存储(并包括设备和位置的字段) )。

这适合您的可寻址空间,但可能不适合(至少连续)在物理内存中。

如果有人知道Linux如何做到这一点,我有兴趣听听它。