【问题标题】:C++ memory leak float pointerC++内存泄漏浮点指针
【发布时间】:2015-11-02 15:55:10
【问题描述】:

我的代码有点奇怪。我有这个内存泄漏并找到它。根据任务管理器,大约是 4KB/秒。这段代码每秒被调用 60 次。

void Shader::setUniform(std::string uniformName, mat4 value){
    float* matValue = value->getM();
    glUniformMatrix4fv(uniforms.find(uniformName)->second, 1, GL_TRUE, matValue);
    free(matValue);
}

作为一个 4x4 矩阵,它是一个包含 16 个浮点数的浮点数*。每秒 60 次,这会泄漏 16(tiems)*4(size of float)*60(times/sec)=3840 字节。它符合任务管理器所说的。问题是,这里为什么会出现内存泄漏?

我尝试注释掉第 3 行并且泄漏不再存在。所以看起来获取数组并删除它不会泄漏内存,但调用 glUniformMatrix4fv() 会。为什么会这样?我不知道。


我的矩阵类是这样的:

class mat4{
    public:
    mat4();
    mat4(const mat4& orig);
    virtual ~mat4();
    mat4* initIdentity();
    mat4 operator+(mat4 other);
    mat4 operator+(float value);
    mat4 operator-(mat4 other);
    mat4 operator-(float value);
    mat4 operator*(mat4 other);
    mat4 operator*(float value);
    bool operator==(mat4 other);
    bool operator!=(mat4 other);
    mat4* initTranslation(float x, float y, float z);
    void setM(float* m);
    float* getM() const;
    float get(int row, int col) const;
    void set(float value, int row, int col);
private:
    float* m;
};

实现是:

mat4::mat4(){
    m = (float*)malloc(16*sizeof(float));
}
mat4::mat4(const mat4& orig){
    m = (float*)malloc(16*sizeof(float));
    for(int i=0; i<16; i++)
        m[i] = orig.m[i];
}
mat4::~mat4(){
    free(m);
}
mat4* mat4::initIdentity(){
    m[0]=1;     m[1]=0;     m[2]=0;     m[3]=0;
    m[4]=0;     m[5]=1;     m[6]=0;     m[7]=0;
    m[8]=0;     m[9]=0;     m[10]=1;    m[11]=0;
    m[12]=0;    m[13]=0;    m[14]=0;    m[15]=1;
    return this;
}
mat4* mat4::initTranslation(float x, float y, float z){
    m[0]=1;     m[1]=0;     m[2]=0;     m[3]=x;
    m[4]=0;     m[5]=1;     m[6]=0;     m[7]=y;
    m[8]=0;     m[9]=0;     m[10]=1;    m[11]=z;
    m[12]=0;    m[13]=0;    m[14]=0;    m[15]=1;
    return this;
}
mat4 mat4::operator+(mat4 other){
    mat4 result = mat4();
    for(int i=0; i<16; i++)
        result.m[i] = m[i] + other.m[i];
    return result;
}
mat4 mat4::operator+(float value){
    mat4 result = mat4();
    for(int i=0; i<16; i++)
        result.m[i] = m[i] + value;
    return result;
}
mat4 mat4::operator-(mat4 other){
    mat4 result = mat4();
    for(int i=0; i<16; i++)
        result.m[i] = m[i] - other.m[i];
    return result;
}
mat4 mat4::operator-(float value){
    mat4 result = mat4();
    for(int i=0; i<16; i++)
        result.m[i] = m[i] - value;
    return result;
}
mat4 mat4::operator*(mat4 other){
    mat4 result = mat4();
    for(int i=0; i<4; i++)
        for(int j=0; j<4; j++)
            result.m[i*4+j] = m[4*i+0]*other.m[0*i+j]+
                              m[4*i+1]*other.m[1*i+j]+
                              m[4*i+2]*other.m[2*i+j]+
                              m[4*i+3]*other.m[3*i+j];
    return result;
}
mat4 mat4::operator *(float value){
    mat4 result = mat4();
    for(int i=0; i<16; i++)
        result.m[i] = m[i] * value;
    return result;
}
bool mat4::operator==(mat4 other){
    for(int i=0; i<16; i++)
        if(fabsf(m[i]-other.m[i])<=FLT_EPSILON)
            return false;
    return true;
}
bool mat4::operator!=(mat4 other){
    int numEqual = 0;
    for(int i=0; i<16; i++)
        if(fabsf(m[i]-other.m[i])<=FLT_EPSILON)
            numEqual++;
    if(numEqual == 16)
        return false;
    return true;
}
void mat4::setM(float* m)
{
    free(this->m);
    this->m = m;
}
float* mat4::getM() const{return m;}
float mat4::get(int row, int col) const{return m[row*4+col];}
void mat4::set(float value, int row, int col){m[row*4+col]=value;}

getM() 方法是这样的:

float* mat4::getM() const{return m;}

我尝试注释掉所有内容。仅当我将 float* 数组(在本例中为“matValue”)作为最后一个参数传递给 glUniformMatrix4fv() 函数时,它才会泄漏内存。

为了更清楚,我发现 unifrom 为 0 并尝试调用:

glUnifromMatrix4fv(0, 1, GL_TRUE, matValue);

仍然存在内存泄漏。 取消注释所有行没有内存泄漏。即使方法是这样的:

void Shader::setUniform(std::string uniformName, mat4 value){
    glUniformMatrix4fv(0, 1, GL_TRUE, value.getM());
}

不泄漏内存的唯一方法是注释掉函数调用:

void Shader::setUniform(std::string uniformName, mat4 value){
    //glUniformMatrix4fv(0, 1, GL_TRUE, value.getM());
}

但我必须打电话给它,所以我很绝望。


我在这里使用 DrMemory,因为我在 Windows 上。

Link to the leak result by DrMemory

Link to the error result by DrMemory

【问题讨论】:

  • 我们需要知道getM 做了什么。也许是对unforms.find 的调用泄漏了,但是如果不知道这段代码的作用,我们怎么能知道呢?
  • @Sputanofono 我建议在 valgrind 中运行您的代码,以获得(真正的)内存泄漏。任务管理器无法向您显示使用 free() 返回的内存。
  • 这里有很多东西要检查。例如,释放 matValue 是 99% 的错误,因为它应该在 mat4 描述符中释放。是吗?
  • @Sputanofono 在您的 mat4 类中,您还需要非平凡的复制构造函数和赋值运算符(除了析构函数)。如果析构函数有问题,即使调用空函数,内存也会泄漏。您确定 glUniformMatrix4fv 会导致泄漏吗?
  • @Sputanofono 为什么不跳过所有float* m 的东西而只使用std::vector&lt;float&gt; m;?那么很多代码都是多余的,不再需要了。

标签: c++ arrays memory-leaks


【解决方案1】:

void Shader::setUniform(std::string uniformName, mat4 value){
    float* matValue = value->getM();
    glUniformMatrix4fv(uniforms.find(uniformName)->second, 1, GL_TRUE, matValue);
    free(matValue);
}

你通过值传递mat4。这意味着您将从调用者那里复制mat4。当您复制mat4 时,您会为其分配新内存。然后,您可以使用getM() 获得指向该内存的指针。在您使用 free() 之后,matValue 指向的内存就是您的问题开始的地方。 free() 将释放value 创建的内存。然后value 超出范围并调用析构函数。然后,析构函数在您已经调用 free() 的指针上调用 free(),该指针是未定义的行为。

摆脱在setUniform() 中对free() 的调用,因为setUniform() 是一个无效函数,所以你基本上什么都不做,因为你只是在修改一个副本。我相信您打算/应该通过引用传递mat4

void Shader::setUniform(std::string uniformName, mat4& value)

【讨论】:

  • 完成,但仍有泄漏:-/
【解决方案2】:

如果使用OpenGL ES 2.0,根据the documentation of glUniformMatrix4fv(),第三个参数必须是GL_FALSE,否则会产生GL_INVALID_VALUE错误。

Because OpenGL keeps a set of error flags,并且每次调用 glGetError() 都会测试并清除其中一个标志,内存泄漏问题可能是由于 Shader::setUniform() 每次生成一个新的 GL_INVALID_VALUE 错误而永远不会清除.

【讨论】:

  • 试过了,还是有泄漏。
  • this 版本的文档没有指出 transpose 必须是 GL_FALSE
  • @NathanOliver OpenGL 和 OpenGL ES 3.0+ 没有这个限制。
  • 啊。哎呀。我没有看到版本差异。
  • @Sputanofono 尝试在调用 glUniformMatrix4fv() 之后添加对 glGetError() 的调用,看看是否有不同的错误。 GL_NO_ERROR返回了吗?
猜你喜欢
  • 1970-01-01
  • 2013-10-31
  • 2015-12-15
  • 2014-08-25
  • 1970-01-01
  • 2016-05-14
  • 2019-06-18
  • 2014-09-25
  • 1970-01-01
相关资源
最近更新 更多