在一个阵列中分配16GB时,malloc会无声地失败



我正在处理非常大的数据集。我正在尝试在一个单一阵列中分配16GB

出于某种原因,我不知道,如果我试图访问位置(比方说)"6亿",我会发现这个位置不可访问,并且在运行时出现分段错误。

有人知道为什么会发生这种事吗?

我的体系结构是64位的,因此应该可以寻址160亿个地址,或者至少我是这么认为的。

我的电话是:

int* array = (int*) malloc(sizeof(int)* 1000000000 * 4);

谢谢大家!

@ScottChamberlain,@Sanhdirir:它无声地失败了,因为它没有返回空指针。正如您可能已经注意到的,这个数组表示一个矩阵。在以这种方式分配它之前,我尝试用一个指向指针的指针来分配它。这需要更多的内存空间(80亿字节)来保存每个指针的地址。通过这种方式,我杀死了我的程序,而现在我没有,但当我试图访问一些地址时,我会出现分段错误。

edit如果我分配了1.6亿(甚至更多)的10个块,我不会得到任何错误,并且内存已分配。问题在于分配一个大块。我现在的问题是:有没有办法克服这个限制?

edit2@Sanhadrin你的假设都是正确的,除了我使用gcc这一事实。我在这里报告/proc/meminfo/文件的内容 MemTotal: 198049828 kB MemFree: 113419800 kB Buffers: 153064 kB Cached: 5689680 kB SwapCached: 124780 kB Active: 73880720 kB Inactive: 8998084 kB Active(anon): 70843644 kB Inactive(anon): 6192548 kB Active(file): 3037076 kB Inactive(file): 2805536 kB Unevictable: 0 kB Mlocked: 0 kB SwapTotal: 201273340 kB SwapFree: 164734524 kB Dirty: 0 kB Writeback: 0 kB AnonPages: 76915376 kB Mapped: 16376 kB Shmem: 72 kB Slab: 190352 kB SReclaimable: 124660 kB SUnreclaim: 65692 kB KernelStack: 3432 kB PageTables: 259828 kB NFS_Unstable: 0 kB Bounce: 0 kB WritebackTmp: 0 kB CommitLimit: 300298252 kB Committed_AS: 160461824 kB VmallocTotal: 34359738367 kB VmallocUsed: 733424 kB VmallocChunk: 34258351392 kB HardwareCorrupted: 0 kB AnonHugePages: 0 kB HugePages_Total: 0 HugePages_Free: 0 HugePages_Rsvd: 0 HugePages_Surp: 0 Hugepagesize: 2048 kB DirectMap4k: 195520 kB DirectMap2M: 37507072 kB DirectMap1G: 163577856 kB

信息量确实让这个问题很难回答,但看起来:

  • 您使用的是x86-64体系结构
  • 您可能正在运行Linux
  • 你至少有16GB的RAM,但不确定你是否有超过16GB的空闲RAM
  • 您正在使用gcc进行编译,其设置配置为创建64位二进制文件
  • 您对malloc()的调用返回了一个看似有效(非null)的指针
  • 索引到该内存可能会导致分段错误

如果你阅读malloc的手册页,上面写着:

票据

默认情况下,Linux遵循乐观的内存分配策略。这意味着当malloc()返回非NULL时,不能保证内存真的可用。如果系统内存不足,一个或多个进程将被OOM杀手杀死。有关更多信息,请参阅proc(5)中/proc/sys/vm/overcommit_memory和/proc/sys/vm/oom_adj的描述,以及Linux内核源文件Documentation/vm/overommit accounting。

通过阅读man proc,它指出:

/proc/sys/vm/overcommit_memory此文件包含内核虚拟内存记帐模式。值为:

                 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 getting a process "OOM-killed".  Under Linux 2.4, any
          nonzero value implies mode 1.

因此,根据overcommit_memory的设置,malloc()可能会返回一个有效的指针,即使在请求的空间不可用的情况下也是如此,因为当你使用那么多内存时,其他进程将被终止,从而释放出所需的空间。这里的情况并非如此,因为你会立即使用它——这意味着你实际上一开始就没有16GB的可用空间。进一步:

         In mode 2 (available since Linux 2.6), the total virtual
          address space that can be allocated (CommitLimit in
          /proc/meminfo) is calculated as
              CommitLimit = (total_RAM - total_huge_TLB) *
                            overcommit_ratio / 100 + total_swap
          where:
               *  total_RAM is the total amount of RAM on the system;
               *  total_huge_TLB is the amount of memory set aside for
                  huge pages;
               *  overcommit_ratio is the value in
                  /proc/sys/vm/overcommit_ratio; and
               *  total_swap is the amount of swap space.
          For example, on a system with 16GB of physical RAM, 16GB of
          swap, no space dedicated to huge pages, and an
          overcommit_ratio of 50, this formula yields a CommitLimit of
          24GB.
          Since Linux 3.14, if the value in
          /proc/sys/vm/overcommit_kbytes is nonzero, then CommitLimit is
          instead calculated as:
              CommitLimit = overcommit_kbytes + total_swap

因此,至少,你可以更好地防止它过度投入,这样malloc()就会像预期的那样失败——但潜在的问题是,你要求的空间非常大,而你似乎没有。您可以检查/proc/meminfo来查看任何时候实际有多少空闲,以及其他内存统计信息,以了解问题所在以及您的实际限制。

如果您需要分配非常大的内存块,您应该使用操作系统服务将虚拟内存映射到进程;而不是malloc()。

如果你有任何希望在你的系统上分配16GB,你需要这样做。

相关内容

  • 没有找到相关文章

最新更新