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

Can't allocate 2-4 Gb of RAM with new[]/ C++/Linux/ x86_64

本文关键字:64分配 x86 RAM Gb Linux C++      更新时间:2023-10-16

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

源:

#include <cstdio>
int main()
{
 for(int i=0;i<33;i++) { 
  char*a=new char[1<<i];
  *a=1;
  delete[]a; 
  printf("%dn",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

谢谢!测试肯定有一个错误,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<<24 * 4 = 1<<26;所需的总内存为 2*25*(1<<26) 3355443200 字节 + 50*sizeof(指针) 对于 some_array + 50*(new[] 开销的大小)。

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

试试(size_t)1 << i

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


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

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

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

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

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