释放由GLKTextureLoader分配的纹理(GLKTextureInfo对象)

在iOS上开发新手,特别是iOS 5上新的OpenGL相关function,所以我很抱歉如果我的任何问题是如此基本。

我正在devise的应用程序旨在接收相框,并通过OpenGL ES在屏幕上显示它们(graphics人员将接pipe这个并添加我知道很less的实际OpenGLgraphics)。 该应用程序是开发XCode4,目标是运行iOS 5的iPhone4。目前,我使用ARC和GLKitfunction,除了内存泄漏加载图像作为纹理时,所有工作正常。 该应用程序很快就会收到“内存警告”。

具体来说,我想问一下如何释放分配的纹理

@property(retain) GLKTextureInfo *texture; -(void)setTextureCGImage:(CGImageRef)image { NSError *error; self.texture = [GLKTextureLoader textureWithCGImage:image options:nil error:&error]; if (error) { NSLog(@"Error loading texture from image: %@",error); } } 

image是从相机框架构build的石英图像(来自苹果的示例代码)。 我知道问题不在代码的这一部分,因为如果我禁用分配,应用程序不会收到警告。

我相信超级哈克解决scheme,但似乎工作:

在作业之前添加以下内容:

 GLuint name = self.texture.name; glDeleteTextures(1, &name); 

如果有更正式的方式(或者这是官方的方式),如果有人能让我知道,我将不胜感激。

不是一个直接的答案,但我注意到,它不会真的适合评论。

如果您使用GLKTextureLoader在背景中加载纹理以replace现有纹理,则必须删除主线程上的现有纹理。 在完成处理程序中删除纹理将不起作用。

AFAIK这是因为:

  1. 每个iOS线程都需要自己的EAGLContext,所以后台队列有自己的线程和自己的上下文。
  2. 完成处理程序在您传入的队列上运行,这很可能不是主队列。 (否则你不会在后台加载…)

也就是说, 这会泄漏内存

 NSDictionary *options = @{GLKTextureLoaderOriginBottomLeft:@YES}; dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); [self.asyncTextureLoader textureWithContentsOfFile:@"my_texture_path.png" options:options queue:queue completionHandler:^(GLKTextureInfo *texture, NSError *e){ GLuint name = self.myTexture.name; // // This delete textures call has no effect!!! // glDeleteTextures(1, &name); self.myTexture = texture; }]; 

为了解决这个问题,你可以:

  1. 在上传之前删除纹理。 根据您的GL架构如何,可能略有不同。
  2. 在完成处理程序中删除主队列上的纹理。

所以,要解决泄漏,你需要做到这一点:

 // // Method #1, delete before upload happens. // Executed on the main thread so it works as expected. // Potentially leaves some GL content untextured if you're still drawing it // while the texture is being loaded in. // // Done on the main thread so it works as expected GLuint name = self.myTexture.name; glDeleteTextures(1, &name) NSDictionary *options = @{GLKTextureLoaderOriginBottomLeft:@YES}; dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); [self.asyncTextureLoader textureWithContentsOfFile:@"my_texture_path.png" options:options queue:queue completionHandler:^(GLKTextureInfo *texture, NSError *e){ // no delete required, done previously. self.myTexture = texture; }]; 

要么

 // // Method #2, delete in completion handler but do it on the main thread. // NSDictionary *options = @{GLKTextureLoaderOriginBottomLeft:@YES}; dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); [self.asyncTextureLoader textureWithContentsOfFile:@"my_texture_path.png" options:options queue:queue completionHandler:^(GLKTextureInfo *texture, NSError *e){ // you could potentially do non-gl related work here, still in the background // ... // Force the actual texture delete and re-assignment to happen on the main thread. dispatch_sync(dispatch_get_main_queue(), ^{ GLuint name = self.myTexture.name; glDeleteTextures(1, &name); self.myTexture = texture; }); }]; 

有没有办法简单地将纹理的内容replace为相同的GLKTextureInfo.name句柄? 使用glgentextures时,可以使用返回的纹理句柄使用glteximage2d加载新的texinfo数据。 但是对于GLKTextureLoader,似乎每次载入新纹理数据时都会调用glgentextures …