2015-10-19 98 views
1

在这个使用GLKViewController显示红色屏幕的超级简单应用程序中,内存不断增长。如何阻止iOS EAGLContext的内存不断增长?

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个字节被分配并作为该图像中看到的永远不会被释放(注意该瞬时计数是0 IOAccellResource):

IOAccellResource allocations keeps growing

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

Allocation list and stacktrace

内存“泄漏”虽小,但它仍然设法尽管仅不到3分钟跑使用了6.5 MB。

EAGLContext中是否存在错误,或者我能做些什么吗?我注意到(我是iOS开发的新手),苹果公司的其他部分API使用区域分配器,而内存使用情况持续增长,当它真的应该处于某种稳定状态模式时。这让我觉得我错过了一些东西(我试图将它发送给LowMemory,但没有发生)。

+0

不是一个答案,而只是一个建议:从来没有在任何情况下使用GLKView,GLKViewController或Objective-C中的任何其他GLKit组件。只使用矩阵,矢量...不仅这些组件是邪恶和不可预知的,而且当你尝试做一些自定义的事情时,你可能会很快限制你的进度。 –

+0

对于我使用C++的实际渲染。但我至少必须使用'[EAGLContext presentRenderBuffer]'做“缓冲区交换”,对吧? – Kalle

回答

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

在目前需要调用presentRenderbuffer你的上下文中有适当的渲染缓冲区ID。

其余的代码应该是一样的。但请记住,在不需要它时也可以拆除openGL,并且可能会显式删除在GPU上生成的所有缓冲区。

+0

是的,我创建了一个没有我的C++东西的新项目,以确保它不是我的代码以某种模糊的方式创建泄漏。 我发现了一个来自Apple的示例项目(https://developer.apple.com/library/ios/samplecode/GLEssentials/Introduction/Intro.html),它执行您的操作。但是,真的,苹果的东西太糟糕了,你需要自己重写一切,以避免内存泄漏限制了客户可以在一个地方使用我的应用程序的时间!? – Kalle

+0

那么,我发布的代码是现场测试,应该给你没有内存泄漏。 –

+0

现在我已经实现了不使用GLKit的渲染。但是我仍然得到了相同的泄漏,这是因为泄漏发生在'presentRenderbuffer'调用的代码中,这并不令人感到意外。你在运行什么iOS版本?我正在使用9.0.2 你说“上下文已经正确完成,需要使用”,这是否意味着有一个'EAGLContext'实例准备好了某处(我在'initWithCoder中创建了一个新实例:(NSCoder *)编码器在视图中)? – Kalle