我正在使用128GB内存的服务器来进行一些计算.我需要malloc()
一个大小为56120*56120的2D float数组.示例代码如下:
int main(int argc, char const *argv[]) { float *ls; int num = 56120,i,j; ls = (float *)malloc((num * num)*sizeof(float)); if(ls == NULL){ cout << "malloc failed !!!" << endl; while(1); } cout << "malloc succeeded ~~~" << endl; return 0; }
代码编译成功,但是当我运行它时,它说"malloc failed !!!"
.据我计算,只需要大约11GB的内存来容纳整个阵列.在我开始代码之前,我检查了服务器,并且有110GB的可用内存.为什么会发生错误?
我还发现,如果我减少num
到40000,那么malloc将会成功.
这是否意味着可以分配的最大内存有限制malloc()
?
而且,如果我改变分配方式,直接声明这样大小的2D float数组,如下:
int main(int argc, char const *argv[]) { int num = 56120,i,j; float ls[3149454400]; if(ls == NULL){ cout << "malloc failed !!!" << endl; while(1); } cout << "malloc succeeded ~~~" << endl; for(i = num - 10 ; i < num; i ++){ for( j = num - 10; j < num ; j++){ ls[i*num + j] = 1; } } for(i = num - 11 ; i < num; i ++){ for( j = num - 11; j < num ; j++){ cout << ls[i*num + j] << endl; } } return 0; }
然后我编译并运行它.我得到了"Segmentation fault"
.
我怎么解决这个问题?
问题是,你的计算
(num * num) * sizeof(float)
以32位有符号整数计算完成,num = 56120的结果为
-4582051584
然后将其解释为size_t,其值非常大
18446744069127500032
你没有那么多内存;)这就是malloc()
失败的原因.
铸造num
于size_t
中的malloc计算,则预期它应该工作.
正如其他人所指出的那样,在OP的平台上56120*56120
溢出int
数学.那是未定义的行为(UB).
malloc(size_t x)
接受一个size_t
参数,传递给它的值最好使用至少size_t
数学计算.通过反转乘法顺序,这就完成了. 至少在乘法之前扩大到sizeof(float) * num
原因.num
size_t
int num = 56120,i,j; // ls = (float *)malloc((num * num)*sizeof(float)); ls = (float *) malloc(sizeof(float) * num * num);
即使这会阻止UB,但这并不能防止溢出,因为数学上 sizeof(float)*56120*56120
可能仍会超出SIZE_MAX
.
代码可以预先检测潜在的溢出.
if (num < 0 || SIZE_MAX/sizeof(float)/num < num) Handle_Error();
无需投射结果malloc()
.
使用引用变量的大小比调整类型更容易编码和维护.
什么时候num == 0
,malloc(0) == NULL
不一定是内存不足.
全部一起:
int num = 56120; if (num < 0 || ((num > 0) && SIZE_MAX/(sizeof *ls)/num < num)) { Handle_Error(); } ls = malloc(sizeof *ls * num * num); if (ls == NULL && num != 0) { Handle_OOM(); }
int num = 56120,i,j; ls = (float *)malloc((num * num)*sizeof(float));
num
*num
是56120*56120
哪个3149454400
溢出signed int
导致未定义的行为.
40000工作的原因是40000*40000可以表示为int.
更改num
为long long
(或甚至unsigned int
)的类型
这与其他人编写的内容形成对比,但对我来说,将变量num更改为size_t可以进行分配.可能是num*num溢出了malloc的int.使用56120*56120而不是num*num执行malloc应该抛出溢出错误.