0

glDeleteTexture のかなり不快な動作を見つけました。取得したメモリの一部のみを削除します (GPU 側と RAM の速度のためにテクスチャが保存されるため)。 .

すべてのコードを読む必要はありません。これは単なるデモです。実際に glDeleteTextures を使用してメモリをリークしないようにする方法を知りたいです

サンプル コードをコンパイルするには、Qt 4.5 以降が必要です。

グリークプロ

QT += opengl

SOURCES += main.cpp \
    glleak.cpp
HEADERS += glleak.h

main.cpp

#include <QtOpenGL>
#include <QtGui>
#include "glleak.h"

int main(int argc, char** argv){
    QApplication app(argc, argv);
    glleak gll(0);
    gll.show();
    return app.exec();
}

グリーク.h

#ifndef GLLEAK_H
#define GLLEAK_H

#include <QGLWidget>
#include <QMouseEvent>
#include <QDebug>
#include <QList>

class glleak : public QGLWidget
{
    Q_OBJECT
public:
    glleak(QWidget* parent = 0);
    virtual ~glleak();
protected:
    void initializeGL();
    void paintGL();
    void resizeGL(int w, int h);
    void drawScene(GLenum mode);

    void wheelEvent(QWheelEvent* event);

    void hardcoreTexturing();
private:
    QList<GLuint> texels;

};

#endif // GLLEAK_H

glleak.cpp

glleak::glleak(QWidget* parent) :
        QGLWidget(parent)
{
}

glleak::~glleak()
{
}


void glleak::initializeGL(){
    glClearColor(0.0f,0.0f,0.0f,0.0f);
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_MULTISAMPLE);
    glLineWidth (1.5f);
    glPointSize(4.5f);
    glEnable (GL_BLEND);
    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}

void glleak::resizeGL(int w, int h){
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-w/2.0, w/2.0, h/2.0, -h/2.0, -1.0, 1.0);
    glMatrixMode(GL_MODELVIEW);
    glViewport(0, 0, w, h);
    glLoadIdentity();
}

void glleak::paintGL(){
    glPushMatrix();
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    glColor3f(1.0f,1.0f,1.0f);
    drawScene(GL_RENDER);
    glPopMatrix();
}




void glleak::drawScene(GLenum mode){
    qDebug() << "drawed #" << texels.count() << " Textures";
    hardcoreTexturing();
}


void glleak::hardcoreTexturing(){
    glEnable(GL_TEXTURE_2D);
    for ( int i(0); i<texels.count(); ++i){
        glPushMatrix();
        glTranslatef(1.1f*i, 2.2f*i, 0.0f);
        glBindTexture(GL_TEXTURE_2D, texels.at(i));
        glBegin(GL_QUADS);
        {
            glTexCoord2i(0,0);
            glVertex2i(-128,-128);

            glTexCoord2i(0,1);
            glVertex2i(-128,128);

            glTexCoord2i(1,1);
            glVertex2i(128,128);

            glTexCoord2i(1,0);
            glVertex2i(128,-128);

        }
        glEnd();
        glPopMatrix();
    }
    glDisable(GL_TEXTURE_2D);
}


void glleak::wheelEvent(QWheelEvent* event){
    glEnable(GL_TEXTURE_2D);
    int n(50);
    if (event->delta()>0){
        qDebug() << "gen textures";
        for (int i(0); i<n; ++i){
            QImage t("./ballmer_peak.png","png");
            GLuint tex(0);
            glGenTextures(1, &tex);
            glBindTexture(GL_TEXTURE_2D, tex);
            glTexImage2D( GL_TEXTURE_2D, 0, 3, t.width(), t.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, t.bits() );
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
            glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
            texels.append(tex);
        }
    }
    else{
        qDebug() << "del textures";
        for (QList<GLuint>::iterator i(texels.begin()); i!=texels.end();){
            glDeleteTextures(1, &(*i));
            i = texels.erase(i);
            if (--n <= 0)
                break;


        }
    }
    glDisable(GL_TEXTURE_2D);
        updateGL();
}

ballmer_peak.png ロードしてレンダリングするイメージ

注: デモのコンパイル: すべてをフォルダーに入れ、画像の名前をballmer_peak.pngに変更し、qmake、make、./glleak を呼び出します。 注:デモの使用法:マウスホイールを使用して一度に 50 個のテクスチャを生成または削除します。

glDeleteTextures を完全に間違って使用している場合は、使用方法を教えてください。私の使用法は公式の OpenGL glDeleteTexturesの使用法に準拠しているため、私はアイデアから外れています。

4

7 に答える 7

1

サンプル コードは実行しませんでしたが、Windows7-64 ビットでも同様の結果が得られます。テクスチャごとの glGenTextures() と glDeleteTextures() を使用すると、メモリ リークが発生する可能性がありますが、スレッドのハンドル数が増加しています (たとえば、TaskManager で、ソースからも確認できます)。glDeleteTextures() がハンドルを解放していないようです。おそらく後でそれを行うでしょうが、24 時間のテストでは、ハンドルを決して解放しないことが示されています。ドライバー内部のリークのようです (nVidia GTX285、ドライバー 270.61)。最終的に、実際にプログラムはメモリを使い果たします。私はそれがドライバーの問題だと思い始めています...

于 2011-05-25T12:44:47.510 に答える
1

これがリークの理由である場合とそうでない場合がありますが、まず、glGenTextures を間違って使用しています。

1) テクスチャを初期化する for ループ内にこれを配置しないでください。ループの前に配置して、必要なテクスチャの数を最初のパラメータとして ONCE と呼ぶ必要があります。n == 50 とします。

glGenTextures(50, &tex);

2) tex は n Gluints の静的配列である必要があり、glDeleteTextures が再度呼び出されるまで (自動変数ではありません!) 永続化する必要があります。ループではありません:

glDeleteTextures(50, &tex);

tex は、テクスチャ ID を格納するためのリポジトリと考えてください。(OpenGLリファレンスで指定されているように)テクスチャIDが連続した整数のセットになるという保証はないため、これを使用し、テクスチャをバインドするために行ったように別のQListを言わないことが重要です。内部的に OpenGL が各テクスチャの生成に使用したローカル (自動) 変数への元のポインタを失い、テクスチャ メモリが孤立するため、リークが発生すると想像してください。

お役に立てれば!

于 2011-04-14T03:06:59.777 に答える
0

私はこれを間違っているかもしれませんが、あなたのコードをコンパイルして実行したとき、何の問題もありませんでしたか? 最大 650 のテクスチャ (これ以上増やすことはできません。「killed」メッセージが表示されます) に戻ると、RAM の使用率が 1% から 24% に上がり、1% に戻ります。約 200 まで上げたり下げたりしても問題はありません。RAM の使用率は最後でも 1% のままです。私が理解していることから、これはあなたのシステムに大規模なリークを引き起こしたでしょうか? Ubuntu 10.10 はこちら (Qt 4.7.0)。

于 2011-03-26T13:16:31.767 に答える
0

コードに問題があるように見えるものは何もありません。だから...メモリリークがあると思う理由は何ですか? 特にリークがテクスチャだと思う理由は何ですか?

使用している OpenGL 実装がリークする可能性はありますが、ほとんどありません。それは実装固有です。

メモリ リークを調べるために使用するメカニズムが何であれ、OpenGL コンテキストを解放するとどうなるでしょうか。

于 2010-02-20T14:55:43.097 に答える
0

wheelEvent の先頭でmakeCurrent()を呼び出す必要がある場合があります。

paintEvent、resizeEvent などの場合、Qt は paintGL/resizeGL/etc を呼び出す前にこれを処理する実装を提供しますが、wheelEvent などの他のイベントについては自分で行う必要があります。

于 2010-02-20T15:27:11.837 に答える
-1

私のシステムでのテストはメモリをよく消費し、すべてのテクスチャを削除してもすぐにメモリを解放しませんが、しばらく待つとメモリがシステムに返されます。OGL ドライバーは、遅延メモリ解放アルゴリズムを使用しているようです。

于 2012-01-10T18:52:23.973 に答える