我的工作站具有128GB内存。我无法分配占用(连续)内存超过〜16GB的数组。但是我可以分配多个数组,每个数组大约需要15GB。
示例代码:
#include <stdlib.h>
#include <iostream>
using namespace std;
int main(int argc, char **argv)
{
int MM = 1000000;
int NN = 2200; // 2000 is okay, used ~16GB memory; 2200 produces Segmentation fault
double* testMem1d;
testMem1d = (double*) malloc(MM*NN*sizeof(double));
double* testMem1d1; // NN=2000, allocate another array (or two) at the same time is okay
testMem1d1 = (double*) malloc(MM*NN*sizeof(double));
cout << "testMem1d allocated" << endl;
cin.get(); // here is okay, only malloc but not accessing the array element
cout << "testMem1d[MM*NN-1]=" << testMem1d[MM*NN-1]<< endl;
cout << "testMem1d1[MM*NN-1]=" << testMem1d1[MM*NN-1]<< endl;
// keep running and check the physical memory footprint
for (int tt=0;tt<1000;tt++)
{
for (int ii=0; ii<MM*NN; ii++)
{
testMem1d[ii]=ii;
testMem1d1[ii]=ii;
}
cout << "MM=" << MM << ", NN=" << NN << ", testMem1d[MM*NN-1]=" << testMem1d[MM*NN-1]<< endl;
}
}
如果这不是本质问题,请忽略我在c ++中使用malloc()。 (是吗?)出于其他原因,我需要/想要使用malloc()。
一些观察: (1)分配多个阵列,每个阵列小于15GB是可以的 (2)仅malloc()可以。访问数组元素时出现“分段错误”。
我认为可能存在某些限制内存分配的系统设置。从“ ulimit -a”看来,一切都很好。由于该程序可以访问64位虚拟地址空间,因此我找不到任何仅限制连续内存分配的原因。
OS:Ubunt 16.04。我尝试了mcmodel = large的g ++和icc。似乎无关紧要。
uname -a
Linux 4.4.0-143-generic #169-Ubuntu SMP Thu Feb 7 07:56:38 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 515031
max locked memory (kbytes, -l) unlimited
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) unlimited
cpu time (seconds, -t) unlimited
max user processes (-u) 515031
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
编辑:
(1)mallc()实际上返回NULL [给mcleod_ideafix]
(2)[to zwol]
free -m
total used free shared buff/cache available
Mem: 128809 18950 107840 1129 2018 107910
Swap: 974 939 35
答案 0 :(得分:6)
乘法MM*NN*sizeof(double)
保持关联性,因此它以(MM * NN) * sizeof(double)
的形式发生。在具有等式int
的32位MM * NN
的平台上,它等于2200000000
,无法在32位int
中表示,并且溢出(发生未定义的行为)并环绕产生-2094967296
。然后,将此值提升为sizeof(double)
的通用类型,提升为size_t
。这是有符号类型到无符号类型的转换,其中不能以无符号类型表示有符号的值,因此转换是实现定义的。在具有64位size_t
的二进制补码中,会发生符号扩展,这将导致18446744071614584320
。然后,将这个值乘以sizeof(double)
(我假设它等于8
),它将多次溢出(这是安全的,size_t
是无符号的),并产生18446744056949813248
个字节。您的计算机没有太多的内存,因此malloc
返回NULL。
这就是为什么最好在sizeof
调用中将malloc
作为第一个操作数:
malloc(sizeof(double) * MM * NN);
在这种情况下,操作数将在乘法之前提升为size_t
。
那还不够,因为在testMem1d[MM*NN-1]
和ii<MM*NN
中仍然会发生溢出。因此,您应该将MM
和NN
的类型更改为具有足够位数以容纳结果的类型。
size_t MM = 1000000;
size_t NN = 2200;
或在每次可能溢出的乘法之前将值强制转换为适当的类型。
请注意,语句cout << "testMem1d[MM*NN-1]=" << testMem1d[MM*NN-1]<< endl; cout << "testMem1d1[MM*NN-1]=" << testMem1d1[MM*NN-1]<< endl;
正在读取未初始化的内存。
在C ++中更喜欢使用new
。