无法使用新的[] / C ++ / Linux / x86_64分配2-4 Gb的RAM

时间:2011-05-16 22:29:03

标签: c++ linux memory-management x86-64

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

来源:

#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

内存没有ulimit:

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

为什么会出错?

Glibc为2.3.4,内核为2.6.9

更新:编译器是gcc4.1

谢谢!测试肯定有错误,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 -x c - && ./a.out; echo $?
4

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

4 个答案:

答案 0 :(得分:14)

C中的裸常量是int。签名的int。 所以1 << 31是-2147483648。 因为 1<<31 = 0x10000000 = -2147483648

尝试(size_t)1 << i

答案 1 :(得分:5)

编辑:我在其他答案中看到该问题很可能与传递给new[]的数字变为负数有关。我同意这种情况很可能就是这种情况,我只是因为我认为它包含的信息可能与某些类似情况相关,而问题不在于使用负数调用new[]。< / p>


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

请注意,即使您有超过1Gb的内存可用于此过程,mallocfreenew[]delete[]下面调用的内存可能不会提供内存回到系统,实际上它们可能保留了每个获取/释放的块,因此程序的内存占用量可能高达2Gb(必须使用内核中的malloc实现来检查)尽可能多的实现确实给出了大块。)

最后,当你请求一个1Gb的数组时,你正在请求1Gb的连续的内存,而且可能只是你有更多的内存,但没有一个块足够大特别要求。

答案 2 :(得分:0)

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

答案 3 :(得分:0)

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