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

osg*_*sgx 6 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);
 }
}
Run Code Online (Sandbox Code Playgroud)

跑:

$ 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
Run Code Online (Sandbox Code Playgroud)

内存没有ulimit:

virtual memory          (kbytes, -v) unlimited
data seg size           (kbytes, -d) unlimited
Run Code Online (Sandbox Code Playgroud)

为什么错误?

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];
Run Code Online (Sandbox Code Playgroud)

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

int的大小是4个字节:

$ echo 'main(){return sizeof(int);}'| gcc -x c - && ./a.out; echo $?
4
Run Code Online (Sandbox Code Playgroud)

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

idz*_*idz 14

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

尝试 (size_t)1 << i

  • 好吧,告诉你我看不到的代码可能有什么问题是很棘手的 - 我很好,但我不是那么好;-)查看@DavidRodríguez和@Ben Voigt上面的答案.他们讨论了可能发挥作用的其他因素. (2认同)

Dav*_*eas 5

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


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

请注意,即使您有超过1Gb的内存可用于该进程,malloc并且free(在下面调用new[]并且delete[]可能不会将内存返回给系统,并且它们实际上可能保留每个已获取/已释放的块,因此你的计划可能会在高达2GB的内存占用(必须与你的内核malloc的执行情况进行检查,因为许多实现并给回大块).

最后,当您请求1Gb的数组时,您正在请求1Gb的连续内存,并且可能只是您拥有更多内存,但没有一个块足够大以满足该特定请求.

  • @dribeas:好想,但这是错的.Linux默认情况下具有过度使用行为,您实际上并不需要任何RAM或交换空间来进行分配,并且当您尝试访问已经(显然已成功)已分配的内存时,您的程序可以在没有追索权的情况下被杀死.连续性也是地址空间的问题,而不是可用的RAM,因为页表可以将连续的地址映射到分段的物理RAM.在x86_64下,碎片化的地址空间不太可能成为问题. (2认同)