1

我几乎完成了我的应用程序。其中一个视图使用 GLKit。我只是记忆有问题。基本上发生的情况是,当显示 GLKView 时,内存消耗不断增加(通过 Instruments 看到)。在某个时刻,它显然会崩溃。我对GLKit不太了解,所以希望你能帮助我。

问题是我正在显示的 3d 箭头。如果我不画它,所有其他的东西都不会造成任何问题。这是包含箭头顶点数据的头文件:

#import <GLKit/GLKit.h>

struct arrowVertexData
{
    GLKVector3      vertex;
    GLKVector3      normal;
    GLKVector2      texCoord;
};
typedef struct arrowVertexData arrowVertexData;
typedef arrowVertexData* vertexDataPtr;


static const arrowVertexData MeshVertexData[] = {
    {/*v:*/{{-0.000004, 0.0294140, -0.0562387}}, /*n:*/{{0.000000, 1.000000, 0.000000}}, /*t:*/{{0.500000, 0.333333}}},
... etc...

这是绘制代码:

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    [self.arrowEffect prepareToDraw];
    //glGenVertexArraysOES(1, &arrowVertexArray);
    //glBindVertexArrayOES(arrowVertexArray);

    glGenBuffers(1, &arrowVertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, arrowVertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(MeshVertexData), MeshVertexData, GL_STATIC_DRAW);

    glEnableVertexAttribArray(GLKVertexAttribPosition);
    glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(arrowVertexData), 0);
    glEnableVertexAttribArray(GLKVertexAttribNormal);
    glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_TRUE, sizeof(arrowVertexData), (void *)offsetof(arrowVertexData, normal));
    glBindVertexArrayOES(arrowVertexArray);

    // Render the object with GLKit

    glDrawArrays(GL_TRIANGLES, 0, sizeof(MeshVertexData) / sizeof(arrowVertexData));

    //reset buffers
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

    //disable atttributes
    glDisableVertexAttribArray(GLKVertexAttribNormal);
    glDisableVertexAttribArray(GLKVertexAttribPosition);
}

有什么建议吗?非常感谢您的帮助!

4

2 回答 2

2

每次调用 drawInRect 时,您都在创建一个新的顶点缓冲区 (VBO),并且永远不会删除它们。GLGenBuffers 和 GLBindBuffer 设置了一个新的缓冲区并使其成为当前缓冲区,但真正的损害是由 GLBufferData 完成的,它将数据复制到新的缓冲区中。

glBindBuffer(GL_ARRAY_BUFFER, 0); 将 GL 重置为不使用缓冲区,并且 glDisableVertexAttribArray(GLKVertexAttribPosition); 告诉 GL 不要再在缓冲区中查找位置数据,但是这些调用都没有做任何事情来释放内存。如果您想每次都释放内存,则需要调用 GLDeleteBuffers(1, &arrowVertexBuffer); 释放内存。

更好的方法是在启动时生成缓冲区并在终止时将其删除,并挂在 arrowVertexBuffer 上,每次都根据需要重新绑定和解除绑定,就像重置指针一样出售,假设程序的其他部分正在修改 GL状态。

看起来您也开始使用顶点数组对象 (VAO),这将是另一种捕获状态以供重用的方式,尽管最好等到 VBO 正常工作后再尝试。VBO 和 VAO 都是缓存状态的方法,它们随着时间的推移而发展,以减少每次通过渲染循环的负载,但 VAO 投下了更广泛的网络,这可能会使正确处理变得更加棘手。

作为一般建议,您可以通过添加更通用和流行的标签(例如 [Open GL])来获得对此类问题的更多关注。

Another debugging tool you should definitely try is OpenGL Profiler. If you did not install it with XCode, look it up in the documentation and you should find a link to download the graphic tools package. The resources window will allow you to track the buffer objects in use.

于 2012-10-17T06:07:15.050 回答
0

您是否尝试过在 Xcode 中运行静态分析器?

它非常擅长指出未释放的分配内存之类的东西。

要使用它,请将鼠标按住“运行”按钮并从下拉列表中选择“分析”。

如果它确实找到了任何东西,它通常会用蓝色指出它们,你可以看到这些行追溯到内存被分配和未释放的位置,等等......

让我知道这是否有任何影响。

于 2012-10-03T19:58:48.100 回答