如何阻止iOS EAGLContext的内存增长?

时间:2015-10-19 08:58:27

标签: ios objective-c memory opengl-es

在这个使用GLKViewController显示红色屏幕的超级简单应用中,内存不断增长。

ViewController.h:

#import <UIKit/UIKit.h>
#import <GLKit/GLKit.h>

@interface ViewController : GLKViewController
@end

ViewController.m:

#import "ViewController.h"

@interface ViewController ()
@end

@implementation ViewController {
    EAGLContext* context;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
    GLKView* view = (GLKView*)self.view;
    view.context = context;
    view.drawableDepthFormat = GLKViewDrawableColorFormatRGBA8888;
    [EAGLContext setCurrentContext:context];

    self.preferredFramesPerSecond = 60;
}

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

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}

@end

对于每个帧,分配了9 * 64个字节,并且从未释放,如此图像所示(请注意IOAccellResource的瞬态计数为0):

IOAccellResource allocations keeps growing

这就是分配列表和堆栈跟踪的样子:

Allocation list and stacktrace

记忆&#34;泄漏&#34;尽管只运行不到3分钟,它仍然可以使用6.5 MB。

EAGLContext中是否有错误或者我可以做些什么呢?我注意到(我是iOS开发的新手),Apple的API的其他部分使用区域分配器,并且当它真的应该处于某种稳态模式时,内存使用量会不断增长。这让我觉得我错过了一些东西(我试图发送它LowMemory但没有发生任何事情)。

2 个答案:

答案 0 :(得分:0)

因此,根据您的评论,您说您正在使用其他一些用C ++编写的代码,基本上您只需要连接到要呈现的实际缓冲区。我会假设你提到的那些“C ++”代码都没有膨胀你的记忆而你实际上只是尝试创建一个新的应用程序,只添加你发布的代码只是为了100%肯定...

迁移GLKit对您来说非常简单。只需将用于绘图的UIView子类化,并添加一些方法:

这需要被覆盖,以便您可以从视图中获取渲染缓冲区

+ (Class)layerClass {
        return [CAEAGLLayer class];
}

上下文已经正确完成,需要使用。

您需要手动设置缓冲区。我使用自定义类,但我相信你将能够看到这里发生了什么,并可能删除你不需要的代码。

- (void)loadBuffersWithView:(UIView *)view
{
    self.view = view;

    CAEAGLLayer *layer = (CAEAGLLayer *)view.layer;
    layer.opaque = YES;

    if ([[UIScreen mainScreen] respondsToSelector:@selector(displayLinkWithTarget:selector:)]) {
        layer.contentsScale = [UIScreen mainScreen].scale;
    }

    GLuint frameBuffer; // will hold the generated ID
    glGenFramebuffers(1, &frameBuffer); // generate only 1
    self.frameBuffer = frameBuffer; // assign to store as the local variable
    [self bindFrameBuffer];

    GLuint renderBuffer; // will hold the generated ID
    glGenRenderbuffers(1, &renderBuffer); // generate only 1
    self.renderBuffer = renderBuffer; // assign to store as the local variable
    [self bindRenderBuffer];

    [self.context.glContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:layer];

    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, self.renderBuffer);

    GLint width, height;
    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width);
    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height);
    self.bufferSize = CGSizeMake(width, height);

    glViewport(0, 0, width, height);

    [GlobalTools framebufferStatusValid];
    [GlobalTools checkError];
}

目前,您需要使用适当的渲染缓冲区ID在您的上下文中调用presentRenderbuffer

其余代码应该相同。但是请记住在不需要时也拆除openGL,并可能明确删除GPU上生成的所有缓冲区。

答案 1 :(得分:0)

我在屏幕上打印了常驻内存量,并注意到当设备与调试器断开连接时内存没有增加。

事实证明使用“Zombie instrument”导致了这个......我发誓我看到调试器的内存视图中的内存增加,但现在我不能重复它(没有改变任何东西)在计划中)。