C OpenGL内存泄漏

C++ OpenGL memory leak

首先,我是 c 的初学者。
我正在编写自己的游戏引擎。
代码如下。

Sprite.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include"Sprite.h"


Sprite::Sprite(GLfloat x, GLfloat y, GLfloat width, GLfloat height, Shader& shader, char *texturePath)
{
    init(x, y, width, height, shader, texturePath, STBI_rgb_alpha);
}

Sprite::Sprite(GLfloat x, GLfloat y, GLfloat width, GLfloat height, Shader& shader, char *texturePath, int reg_comp)
{
    init(x, y, width, height, shader, texturePath, reg_comp);
}
void Sprite::init(GLfloat x, GLfloat y, GLfloat width, GLfloat height, Shader& shader, char *texturePath, int reg_comp)
{
    this->shader = &shader;
    GLfloat vertices[] = {
        width/2+x,  height/2+y, 0.0f,  /* Top Right */                  1.0f, 1.0f,
        width/2 + x, -height / 2 + y, 0.0f,  /* Bottom Right*/          1.0f, 0.0f,
        -width/2 + x, -height / 2 + y, 0.0f,  /* Bottom Left*/          0.0f, 0.0f,
        -width / 2 + x,  height / 2 + y, 0.0f,   /* Top Left */         0.0f, 1.0f
    };
    GLuint indices[] = {
        0, 1, 3,  // 1
        1, 2, 3   // 2
    };
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);

    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    //Position
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);
    // TexCoord
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(1);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
    texture = new Texture(texturePath, reg_comp);
    transformShaderLocation = glGetUniformLocation(shader.program,"transform");
    glProgramUniform4fv(shader.program, transformShaderLocation, 1, transform);

}


Sprite::~Sprite()
{
    delete texture;
}


void Sprite::Draw() {
    glBindTexture(GL_TEXTURE_2D, texture->texture); //?
    //glUniform1i(glGetUniformLocation(shader->program,"ourTexture"), 0); //?
    shader->Use();
    glBindVertexArray(VAO);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);
}


void Sprite::Transform(int x, int y) {
    glProgramUniform4fv(shader->program, transformShaderLocation, 1, transform);
}

void Sprite::setTexture(Texture *texture) {
    delete this->texture;
    this->texture = texture;
}

Sprite.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#pragma once
#include <GL/glew.h>
#include"Shader.h"
#include <glm/glm.hpp>
#include"Texture.h"
#include <stb_image.h>



class Sprite
{
public:
    Sprite(GLfloat x, GLfloat y, GLfloat width, GLfloat height, Shader& shader, char *texturePath);
    Sprite(GLfloat x, GLfloat y, GLfloat width, GLfloat height, Shader& shader, char *texturePath, int reg_comp);

    ~Sprite();
    void Draw();
    void Transform(int x, int y);
    void setTexture(Texture *texture);

private:
    void init(GLfloat x, GLfloat y, GLfloat width, GLfloat height, Shader& shader, char *texturePath, int reg_comp);
    GLuint VBO = 0, VAO = 0, EBO = 0;
    GLint transformShaderLocation;
    Shader* shader;
    GLfloat transform[4] = {
        1.f, 1.f, 1.f, 1.f
    };
    Texture *texture;

};

纹理.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include"Texture.h"


Texture::Texture(char *texturePath, int reg_comp)
{
    glGenTextures(1, &texture);

    int _width, _height, _ImageComponents;

    unsigned char *image = stbi_load(texturePath, &_width, &_height, &_ImageComponents, reg_comp);
    if (image == nullptr) {
        std::cout <<"error loading image" << std::endl;
    }


    glBindTexture(GL_TEXTURE_2D, texture);


    // Set our texture parameters
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);  
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    // Set texture filtering
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    //glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _width, _height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);

    if (_ImageComponents == 3)
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _width, _height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
    else if (_ImageComponents == 4)
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _width, _height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image); //RGBA8?


    glGenerateMipmap(GL_TEXTURE_2D);

    glBindTexture(GL_TEXTURE_2D, 0);
    stbi_image_free(image);
}


Texture::~Texture()
{
}

纹理.h

1
2
3
4
5
6
7
8
9
10
11
12
13
#pragma once
#include <GL/glew.h>
#include <iostream>
#include <stb_image.h>


class Texture
{
public:
    Texture(char *texturePath, int reg_comp);
    ~Texture();
    GLuint texture = 0;
};

main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include"main.h"
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>




int main(int argc, char* argv[]) {
    Main main;
    return main.init();
}
int Main::init() {

    display = new Display( 800, 600,"OpenGL" );
    shader = new Shader("Shaders/default.vert","Shaders/default.frag");

    sprite = new Sprite(-0.5f, -0.5f, 1.0f, 1.0f, *shader,"Textures/texture1.png");
    sprite2 = new Sprite(0.5f, 0.5f, 1.0f, 1.0f, *shader,"Textures/texture2.png", STBI_rgb);



    while (!display->isClosed()) {
        update();
    }
    delete display;
    delete shader;
    delete sprite;
    delete sprite2;
    return 0;
}

void Main::update() {

    draw();
    display->Update();

    if (debug == 0) {
        texture->setTexture(new Texture("Textures/texture1.png", STBI_rgb_alpha));
        debug = 1;
    }
    else if (debug == 1) {
        texture->setTexture(new Texture("Textures/texture2.png", STBI_rgb));
        debug = 0;
    }

}

void Main::draw() {
    glClearColor(0.0f, 0.3f, 0.5f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);;
    sprite->Draw();
    sprite->Draw();
}

main.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#pragma once
#include <iostream>
#include"Display.h"
#include"Shader.h"
#include"Triangle.h"
#include"Sprite.h"



class Main {
public:
    int init();

private:
    void draw();
    void update();
    Display *display;
    Shader *shader;
    Triangle *triangle, *triangle2;
    Sprite *sprite, *sprite2;
    int debug = 0;
};

您会看到,每次创建新纹理时,都会删除最后一个纹理。
但是,如果我打开任务管理器,内存使用量就会上升。
为什么呢?
(如果我删除 setTexture(new...) 一切都很好,所以这就是问题所在。


你的 glDelete… 调用在哪里? (glDeleteTexturesglDeleteBuffers)。除非您在析构函数中显式执行此操作,否则使用 delete 运算符重新分配您的类实例不会神奇地使用 OpenGL 执行正确的删除步骤。


当我编写 OpenGL 的东西时,我现在在所有句柄周围使用package器。如果您使用 GLuint,很可能会忘记一些设置或删除代码。根据您的编码技能,这些package器可能非常通用,或者您可以为此目的使用共享指针。