Linux kernel 为什么在大于4GB的(稀疏)文件上使用ENOMEM时COW mmap会失败?

Linux kernel 为什么在大于4GB的(稀疏)文件上使用ENOMEM时COW mmap会失败?,linux-kernel,mmap,copy-on-write,Linux Kernel,Mmap,Copy On Write,这发生在2.6.26-2-amd64 Linux内核上,当尝试使用写时复制语义(PROT_READ | PROT_write和MAP_PRIVATE)映射5GB文件时。映射小于4GB的文件或仅使用PROT_READ可以正常工作。这不是中报告的软资源限制问题;虚拟限制大小是无限的 下面是重现问题的代码(实际代码是问题的一部分) 以下是nos要求的相关strace(新编译的4.5.20)输出 open("foo.bin", O_RDWR) = 3 fstat(3, {

这发生在2.6.26-2-amd64 Linux内核上,当尝试使用写时复制语义(PROT_READ | PROT_write和MAP_PRIVATE)映射5GB文件时。映射小于4GB的文件或仅使用PROT_READ可以正常工作。这不是中报告的软资源限制问题;虚拟限制大小是无限的

下面是重现问题的代码(实际代码是问题的一部分)

以下是nos要求的相关strace(新编译的4.5.20)输出

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

尝试在
标志
字段中传递
MAP\u NORESERVE
,如下所示:

mmap(NULL, b.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_NORESERVE, fd, 0);
您的交换和物理内存的组合可能小于5GB的请求

或者,您可以出于测试目的执行此操作,如果它有效,您可以更改上面的代码:

# echo 0 > /proc/sys/vm/overcommit_memory
以下是手册页面的相关摘录

mmap(2):

程序(5):


引用评论中的内存、交换大小和过度限制设置:

MemTotal: 4063428 kB SwapTotal: 514072 kB
$ cat /proc/sys/vm/overcommit_memory
0
$ cat /proc/sys/vm/overcommit_ratio 
50
overmit\u memory
设置为0(“启发式overmit”)时,您无法创建大于当前可用内存和交换总量的私有可写映射-很明显,因为您只有4.5GB的内存+交换,这永远不会是真的


您可以选择使用
MAP\u NORESERVE
(如建议的那样),前提是您确保不会在映射中脏(写)到超过可用内存和交换空间的页面;或者显著增加交换空间的大小。

您可以在
strace
下运行此程序并显示输出吗?是的,请这样做。FWIW您的配方在amd64上的2.6.35不会对我产生任何错误。完成(请参阅原始问题)。内存
/proc/sys/vm/overmit\u和
/proc/sys/vm/overmit\u比率
的值是多少?你有多少物理内存和交换空间?内存总量:4063428 kB交换总量:514072 kB$cat/proc/sys/vm/overmit_内存0$cat/proc/sys/vm/overmit_比率50就是这样!写入时复制要求整个文件具有相应的备份存储。知道我只打算修改几页,这不是通灵。我将修补Boost,并与作者联系,提出相应的选项。@Diomidis Spinellis:让我们知道请求的进展情况。我想作者故意没有把这个放进去,或者是因为他们提供的mmap代码是POSIX或者不是Linux特定的,或者是为了避免OOM(这就是为什么这不是默认设置的原因)。我想说,实现这一点的更好方法是再添加几次交换,并满足于它们永远不会被使用,但可以保护您免受OOM杀手的任何可能性。@R..:这是真的,很可能是为什么它不是默认行为。
# echo 0 > /proc/sys/vm/overcommit_memory
   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.
   /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.
MemTotal: 4063428 kB SwapTotal: 514072 kB
$ cat /proc/sys/vm/overcommit_memory
0
$ cat /proc/sys/vm/overcommit_ratio 
50