【问题标题】:Why mmap cannot allocate memory?为什么 mmap 不能分配内存?
【发布时间】:2015-02-22 09:46:04
【问题描述】:

我以 root 权限运行该程序,但它一直抱怨 mmap 无法分配内存。代码sn-p如下:

#define PROTECTION (PROT_READ | PROT_WRITE)
#define LENGTH (4*1024)

#ifndef MAP_HUGETLB
#define MAP_HUGETLB 0x40000
#endif

#define ADDR (void *) (0x0UL)
#define FLAGS (MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB)

int main (int argc, char *argv[]){
...
  // allocate a buffer with the same size as the LLC using huge pages
  buf = mmap(ADDR, LENGTH, PROTECTION, FLAGS, 0, 0);
  if (buf == MAP_FAILED) {
    perror("mmap");
    exit(1);
  }
...}

硬件:我有 8G RAM。处理器是ivybridge

无名输出:

Linux mymachine 3.13.0-43-generic #72-Ubuntu SMP Mon Dec 8 19:35:06 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

编辑 1:perror 的输出

mmap: Cannot allocate memory

还加了一行打印errno

printf("something is wrong: %d\n", errno);

但是输出是:

something is wrong: 12

编辑 2:来自 /proc/meminfo 的大量 tlb 相关信息

HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB

【问题讨论】:

  • 你查看errno了吗? [或]perror() 的输出是什么?
  • 我的 OSX 没问题。
  • 你根本不应该定义它,它是一个标志而不是你改变的东西。您的系统没有配置任何大页面,因此该错误看起来很正常。
  • 仅供参考,因为巨大的页面大小是 2MB,但你只分配了 4KB,你浪费了 2044KB

标签: c mmap


【解决方案1】:

当您使用MAP_HUGETLB 时,mmap(2) 调用可能会失败(例如,如果您的系统没有配置大页面,或者某些资源已耗尽),因此您几乎总是应该调用mmap 而没有MAP_HUGETLB作为故障恢复。此外,您不应定义MAP_HUGETLB。如果没有定义(<sys/mman.h> 内部的系统头文件;根据架构或内核版本可能会有所不同),请不要使用它!

// allocate a buffer with the same size as the LLC using huge pages
buf = mmap(NULL, LENGTH, PROTECTION,
#ifdef MAP_HUGETLB
           MAP_HUGETLB |
#endif
           MAP_PRIVATE | MAP_ANONYMOUS,
           0, 0);
#ifdef MAP_HUGETLB
  if (buf == MAP_FAILED) {
    // try again without huge pages:
    buf = mmap(NULL, LENGTH, PROTECTION, 
               MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
  };
#endif
if (buf == MAP_FAILED) {
   perror("mmap");
   exit(EXIT_FAILURE);
}

内核的Documentation/vm/hugetlspage.txt 提到大页面是-或可能-受限的(例如,如果您将hugepages=N 传递给内核,或者如果您通过/proc//sys/ 执行操作,或者如果不是这样在内核中配置等...)。所以你不确定得到它们。使用大页面进行只有 4KB 的小映射是一个错误(或者可能是失败)。大页面仅在要求 许多 兆字节(例如千兆字节或更多)时才值得使用,并且始终是一种优化(例如,您希望您的应用程序能够在没有它们的情况下在内核上运行)。

【讨论】:

  • 我想请 mmap 使用巨大的 tlb。我应该如何让这个错误消失?
  • 为什么mmapMAP_HUGETLB 会失败?请提供一些关于此的链接,mmaphugetlbpage 都没有谈论 mmapMAP_HUGETLB 可能会失败
  • @jujj 和 Basile Starynkevitch,我将映射大小更改为 4*1024*1024 并应用 jujj 提供的 echo 命令。它现在正在工作。但是由于你们俩都提供了部分解决方案,我不知道该回答谁。但是我认为Basile首先发布了内核文档和解释。注意:仅使用 echo 命令,稍后在我的程序中仍然会出现段错误。
  • 但是我还是不明白为什么不能定义MAP_HUGETLB
  • 因为它是由系统头文件提供的。如果他们没有定义它,你的系统就没有它。
【解决方案2】:

好吧,正如Documentation/vm/hugetlspage.txt 建议的那样,做

echo 20 > /proc/sys/vm/nr_hugepages

解决了这个问题。在 ubuntu 14.04 上测试。也检查Why I can't map memory with mmap

【讨论】:

  • 我使用了 VHM,进入服务器配置,然后搜索 proc。我选择了无限制,我的问题在哪里解决了
【解决方案3】:

如果您确定物理内存就足够了,这是一个实用的解决方案:

echo 1 > /proc/sys/vm/overcommit_memory

【讨论】:

  • 这不能解决问题。如果内核没有可用的大页面(它们需要在物理内存中连续),使用MAP_HUGETLB 分配将失败。即使您还有 TB 的可用内存。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-09-21
  • 2016-06-03
  • 1970-01-01
  • 2014-05-11
  • 2013-12-22
  • 2010-12-30
  • 2017-12-15
相关资源
最近更新 更多