【问题标题】:Memory leak caused loading textures, despite calling glDeleteTextures after rendering function尽管在渲染函数后调用 glDeleteTextures,但内存泄漏导致加载纹理
【发布时间】:2015-02-20 16:40:23
【问题描述】:

我正在使用我编写的类加载纹理,如下所示。目的是创建一个新纹理,用存储在数组中的数据加载它,然后将其渲染到屏幕上。纹理创建没有任何问题,并且也被加载。但是,尽管调用 delete 以调用 Texture 类的析构函数来删除纹理,但它会导致应用程序内存大小不断增加的内存泄漏。

void renderCurrentGrid(){    

// Get the current grid (custom wrapper class, it's working fine)
Array2D<real_t> currentGrid = m_Continuum->getCurrentGrid();

// load it as a texture
Texture *currentGridTexture = new Texture(GL_TEXTURE_2D);
currentGridTexture->load(currentGrid.sizeWd(), currentGrid.sizeHt(), &currentGrid(0,0));

......

delete currentGridTexture;
}

纹理类的加载函数:

bool Texture::load(const size_t width, const size_t height, const float *data)
{
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

// Allocate a texture name
glGenTextures(1, &m_TextureObj);

// select current texture
glBindTexture(GL_TEXTURE_2D, m_TextureObj);

// select replace to ensure texture retains each texel's colour
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

// if texture wraps over at the edges
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

glGenerateMipmap(GL_TEXTURE_2D);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE,/* &density(0,0)*/data);

m_Loaded = true;
return true;
}

以及Texture类的析构函数:

Texture::~Texture()
{
glBindTexture(m_TextureTarget, m_TextureObj);
glDeleteTextures(1, &m_TextureObj);
glBindTexture(m_TextureTarget, NULL);
}

纹理类的私有数据成员:

private:
GLenum m_TextureTarget;
GLuint m_TextureObj;

bool m_Loaded;

在这里,我创建了新纹理,并使用纹理类的加载函数加载它。纹理渲染得非常好,但加载会导致内存泄漏。当我在任务管理器上检查时,应用程序内存大小不断增加。

但是,当我注释掉该行时

currentGridTexture->load(....);

内存泄漏停止。我省略了渲染功能,与问题无关。

【问题讨论】:

  • glDeleteTexture 释放 GPU 资源,您似乎正在泄漏 CPU 内存,这是一个完全不同的问题。
  • 好点,它是 CPU,我应该在哪里寻找内存泄漏,因为我现在很难过,因为内存泄漏发生在纹理类?
  • 无关,但值得注意的是:glGenerateMipmap (...) 相对于glTexImage2D (...) 的调用顺序错误。您需要调用 after 将图像上传到纹理 LOD 0 - 否则,没有图像可以从中生成较低分辨率的 mipmap LOD . 现在没关系,因为你没有使用 mipmap 缩小过滤器,但如果你改变它,它会的。
  • 感谢您指出这一点,@Andon。我在生成 mipmap 时遇到了问题,这就是我使用 GL_NEAREST 参数的原因。尽管我在下面的解决方案允许在第二次渲染调用期间生成 mipmap,但这是一个我不会发现的细微差别。切换顺序解决了它。

标签: c++ opengl memory memory-leaks textures


【解决方案1】:

我已经设法解决了上面的问题。在 Texture 类的加载函数中,我调用的是

glGenTextures(1, &m_TextureObj)

调用此函数时,根据OpenGL documentation,第二个参数指定一个数组,其中存储了生成的纹理名称。为了存储纹理,它分配了一定数量的 CPU 内存。

每次渲染更新都会调用加载函数,因此每次在该函数中调用 glGenTextures 时,OpenGL 都会分配资源。虽然 glDeleteTextures 被析构函数调用,理论上应该释放资源,但根据这个 link,情况并非如此,引用如下:

仅仅因为你告诉 OpenGL 你完成了一个纹理对象并不意味着 OpenGL 必须立即放弃该内存。这样做通常需要一些非常繁重的操作。因此,驱动程序会将其推迟到以后。

当我在每次更新时创建和删除纹理时,我想出了一个解决方案,以便我可以使用相同的纹理对象,并使用不同的数据加载它,以防止 OpenGL 每次更新都分配资源。

我将glGenTextures 函数移到Texture 类的构造函数中,以便在实例化Texture 对象时只调用一次。我现在创建一个纹理对象,并在每次更新时加载新数据。

为了确保glGenTextures 函数只被调用一次,我还在渲染函数中移动了纹理对象的实例化和删除,即

Texture *currentGridTexture = new Texture(GL_TEXTURE_2D);
...
delete currentGridTexture;

并将currentGridTexture声明为渲染类的私有数据成员,并在构造函数中实例化它,并在该类的析构函数中将其删除,这样在运行时只创建和删除一个纹理对象我的应用程序,而不是每次更新都创建和删除纹理对象。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-12-06
    • 2011-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多