不能用新的 / C ++ / Linux / x86_64分配2-4 Gb的RAM

对于这个简单的testing,以及具有4Gb或RAM,0byte交换和CPU x86_64模式的linux盒子,我不能分配超过1Gb的数组。

资源:

#include <cstdio> int main() { for(int i=0;i<33;i++) { char*a=new char[1<<i]; *a=1; delete[]a; printf("%d\n",i); fflush(stdout); } } 

跑:

 $ file test test: ELF 64-bit LSB executable, AMD x86-64, version 1 (SYSV) $ ./test ... 24 25 26 27 28 29 30 terminate called after throwing an instance of 'std::bad_alloc' what(): St9bad_alloc Aborted 

记忆没有限制:

 virtual memory (kbytes, -v) unlimited data seg size (kbytes, -d) unlimited 

为什么错误?

Glibc是2.3.4,内核是2.6.9

更新:编译器是gcc4.1

谢谢! testing肯定有一个错误, 1ull<<i给我多达31(2GB)。 这个错误是无意的。 但真正的失败代码是

  for(j=0;j<2;j++) for(i=0;i<25;i++) some_array[j][i] = new int[1<<24]; 

所以实际代码中没有符号溢出。

int的大小是4个字节:

 $ echo 'main(){return sizeof(int);}'| gcc -xc - && ./a.out; echo $? 4 

每个请求将为1 << 24 * 4 = 1 << 26; 所需的总内存是2 * 25 *(1 << 26)3355443200字节+ 50 * sizeof(指针)some_array + 50 *(new []开销的大小)。

编辑:我在其他答案看到,这个问题是最有可能与传递给new[]成为负面的数字有关。 我同意这很可能是这样,我只是留下这个答案,因为我认为它包含的信息在某些类似的情况下可能是相关的,而这个问题不是用一个负数来调用new[]


首先想到的问题是你是否有足够的可用内存。 使用4Gb RAM和不交换,可分配给所有进程内核的内存总量为4Gb。

请注意,即使你有超过1Gb的内存可用于进程, mallocfree (在下面被new[]delete[]调用的内存可能不会把内存回给系统,并且它们实际上可能保留每一个的获取/释放块,所以你的程序的内存占用可能会高达2Gb(将不得不检查与你的内核的malloc实现,因为许多实现返回大块)。

最后,当你请求一个1Gb的数组的时候,你正在请求1Gb的连续内存,这可能就是你拥有更多的内存,但是没有一个块足够大以满足特定的请求。

C中的一个裸常量是一个int。 一个有符号整数。 所以1 << 31是-2147483648。 因为1<<31 = 0x10000000 = -2147483648

试试(size_t)1 << i

/proc/sys/vm/overcommit_memory/proc/sys/vm/overcommit_memory/proc/sys/vm/overcommit_ratio是多少? 如果关闭了内存过量使用功能,则可能无法分配系统上的所有内存。 随着overcommit的开启(将/proc/sys/vm/overcommit_memory为0),你应该可以在64位系统上分配基本上无限大小的数组(当然是10个GB)。

虽然在64位机器上通常是真实的,但您有足够的地址空间来分配几GB连续的虚拟内存,您正尝试使用new / malloc来分配它。 new / malloc通常不是对任何内存的请求,而是对使用{s,} brk系统调用分配的内存的特定部分进行的,该系统调用基本上移动了进程数据段的末尾。 我认为你应该使用mmap分配如此大量的内存,这样可以让操作系统免费选择任何地址块。