内存泄漏导致加载纹理,尽管在渲染函数后调用了 glDeleteTextures

Memory leak caused loading textures, despite calling glDeleteTextures after rendering function

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

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;
}

纹理class'加载函数:

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;
}

和纹理的析构函数class:

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

纹理class'私有数据成员:

private:
GLenum m_TextureTarget;
GLuint m_TextureObj;

bool m_Loaded;

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

然而,当我注释掉这一行时

currentGridTexture->load(....);

内存泄漏停止。我省略了渲染函数,a sit 与问题无关

我已经成功解决了上面的问题。在纹理 class' 加载函数中,我调用

glGenTextures(1, &m_TextureObj)

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

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

Just because you tell OpenGL that you're done with a texture object doesn't mean that OpenGL must immediately relinquish that memory. Doing that generally requires some pretty heavy-weight operations. So instead, drivers will defer this until later.

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

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

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

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

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