“std::bad_alloc”:我使用的内存太多了吗?

31

这个信息:

terminate called after throwing an instance of 'std::bad_alloc'
what():  std::bad_alloc

我查看了gdb的回溯信息,这是我自己实现的最低级别方法:

/*
 * get an array of vec3s, which will be used for rendering the image
 */
vec3 *MarchingCubes::getVertexNormalArray(){
    // Used the same array size technique as getVertexArray: we want indices to match     up
    vec3 *array = new vec3[this->meshPoints.getNumFaces() * 3]; //3 vertices per face

    int j=0;
    for (unsigned int i=0; i < (this->meshPoints.getNumFaces() * 3); i++) {
        realVec normal = this->meshPoints.getNormalForVertex(i);
 //     PCReal* iter = normal.begin();

        if (normal.size() >= 3) {
            array[j++] = vec3(normal[0], normal[1], normal[2]);
        }
        cout << i << " ";
    }

    return array;
}

你在上面看到的cout语句表示它在7000多次迭代后终止。 上述函数仅在我应用程序的末尾附近调用一次。 在调用上述函数之前,我调用了一个非常类似的函数,但没有引起问题。


6
你曾经用 delete[] 释放这个函数返回的数组吗? - Matteo Italia
1
meshPoints.getNumFaces()的大小是多少?vec3的大小又是多少? - celtschk
7
哎呀,那你的内存泄漏很严重啊。顺便说一下,你应该使用智能指针或标准容器;在C++中完全手动管理内存是要避免的,因为这样代码就不会具备异常安全性,并且总是存在内存泄漏的风险。 - Matteo Italia
2
另一个想法,完全不同的方向:你有检查过 j 是否始终保持在 meshPoint.getNumFaces()*3 以下吗?也许你会因为缓冲区溢出而覆盖了必要的堆结构,从而导致 bad_alloc - celtschk
1
啊,好的,那么这可能不是你的问题。程序结尾处的删除并不是严格必要的,因为在程序结束时,操作系统会从程序中回收所有内存,而且你的数组仅包含浮点数,因此你没有漏掉任何析构函数调用。那么 j 怎么样? - celtschk
显示剩余16条评论
2个回答

38

(从评论中移动/扩展)

由于您每次都在分配新的数组而没有释放它,因此您会有一个巨大的内存泄漏,即您继续向系统请求内存而从未将其归还。最终堆上的空间用完了,在下一次分配时,您只会得到一个 std::bad_alloc 异常。

"C风格"的解决方案是记住在不再需要该内存时进行内存释放(使用delete[]),但这种方法容易出错(例如,如果函数内部有多个返回路径)并且存在潜在的异常不安全性(如果有异常,则每个指令都可能成为返回路径!)。因此,应避免使用这种方式。

C++惯用的解决方案是使用 智能指针 - 小型对象,封装指针并在销毁时释放关联的内存 - 或标准容器,它们做更多或更少相同的事情,但具有复制语义和一些其他功能(包括在其中存储数组的大小)。


4

我的问题最终是因为this->meshPoints.getNormalForVertex(i)访问的数组(或向量,我记不清了)长度小于this->meshPoints.getNumFaces() * 3。因此它正在越界访问。


19
这并没有解释 std::bad_alloc 异常:当标准定义的 operator new 和 operator new[] 无法分配所请求的存储空间时,抛出的异常类型。 - uceumern

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接