2015-10-19 101 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