【问题标题】:Why does mmap() fail with ENOMEM on a 1TB sparse file?为什么 mmap() 在 1TB 稀疏文件上使用 ENOMEM 失败?
【发布时间】:2010-05-26 03:31:47
【问题描述】:

我一直在 openSUSE 11.2 x86_64 上处理大型稀疏文件。当我尝试 mmap() 一个 1TB 的稀疏文件时,它会因 ENOMEM 而失败。我原以为 64 位地址空间足以映射 TB,但似乎不是。进一步试验,一个 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;
}

【问题讨论】:

  • 作为一个兴趣点,你的程序适用于我最大 256GB (1 &lt;&lt; 38) 的大小,任何更高的返回 EINVAL。这是在 RHEL4(内核 2.6.9-42.0.3.ELsmp)上。
  • ulimit -a 说什么?
  • 谢谢,bmargulies - 就是这样。 ulimit -a 报告的虚拟内存为 1804800 KB(略高于 1.7GB)。 ulimit -v 1610612736 (1.5TB) 让我映射我的 1TB 稀疏文件。我会回答我自己的问题,这样我就可以“关闭”它......

标签: c linux mmap


【解决方案1】:

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

【讨论】:

  • 而且,显然,我可以在 /etc/profile 中设置我想要的值(可以是“无限”)以使其持久化。
【解决方案2】:

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

【讨论】:

  • 是的 - 我尝试了 bmargulies 的尝试 ulimit -a 的建议,并指出“虚拟内存”进程限制是罪魁祸首 - 请参阅下面的答案...
【解决方案3】:

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

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

如果有人知道更多关于 Linux 是如何做到这一点的,我很想听听。

【讨论】:

  • Linux 不会创建 PTE(页表条目),直到实际触及这些页面。创建映射时它所做的只是创建一个单一的 VMA(虚拟内存区域)结构,该结构基本上包含来自 mmap() 的信息。
猜你喜欢
  • 2016-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-07
  • 2020-06-28
  • 2017-08-24
相关资源
最近更新 更多