当前位置:  开发笔记 > 编程语言 > 正文

为什么当内存足够时malloc()会失败?

如何解决《为什么当内存足够时malloc()会失败?》经验,为你挑选了4个好方法。

我正在使用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".

我怎么解决这个问题?



1> Ctx..:

问题是,你的计算

(num * num) * sizeof(float)

以32位有符号整数计算完成,num = 56120的结果为

-4582051584

然后将其解释为size_t,其值非常大

18446744069127500032

你没有那么多内存;)这就是malloc()失败的原因.

铸造numsize_t中的malloc计算,则预期它应该工作.


num应该是`size_t`而不是'long`
@Ctx`malloc()`取一个`size_t`,使用`size_t`.
@Ctx*对`num`*使用数据类型`long`和*你可以将`(num*num)*sizeof(float)`的结果转换为`size_t`*在Windows上尝试,`long`是即使对于64位应用程序,仍然是32位*signed*值.仍然很讨厌.
@Stargateur为什么会这样?`num`本身不是一个大小,所以`size_t`似乎不合适
@Stargateur我的意思是"将num保留为long并投射结果".num在这个程序中在语义上不是一个`size_t`,因此将它声明为一个在我眼中是彻头彻尾的误导和错误.

2> chux - Reins..:

正如其他人所指出的那样,在OP的平台上56120*56120溢出int数学.那是未定义的行为(UB).

malloc(size_t x)接受一个size_t参数,传递给它的值最好使用至少size_t数学计算.通过反转乘法顺序,这就完成了. 至少在乘法之前扩大到sizeof(float) * num原因.numsize_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();
}



3> Mike Vine..:
int num = 56120,i,j;
ls = (float *)malloc((num * num)*sizeof(float));

num*num56120*56120哪个3149454400溢出signed int导致未定义的行为.

40000工作的原因是40000*40000可以表示为int.

更改numlong long(或甚至unsigned int)的类型


num应该是`size_t`不是'long long`甚至是`unsigned int`.
@UKMonkey`malloc()`取一个`size_t`,使用`size_t`.不要混合类型或你会有像这个问题的问题...
@Stargateur实际上,任何足以容纳数字的类型都可以.一个长的,甚至是无符号的int,它可以容纳一个这么大的数字.
@MikeVine如果`num`表示数组的大小,是的,它应该是`size_t`.或者OP需要正确地投射它.在这里你说"使用很长一段时间",但如果下一次该值不适合"long long"怎么办?你建议改变`num`的类型为什么不使用正确的类型?

4> 小智..:

这与其他人编写的内容形成对比,但对我来说,将变量num更改为size_t可以进行分配.可能是num*num溢出了malloc的int.使用56120*56120而不是num*num执行malloc应该抛出溢出错误.

推荐阅读
360691894_8a5c48
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有