内存警告后,崩溃在iOS上运行OpenGL

我在iPad上遇到OpenGL组件崩溃的问题。 该应用程序抛出一个内存警告和崩溃,但似乎并没有使用那么多的内存。 我错过了什么吗?

该应用程序基于Vuforia增强现实系统(借鉴ImageTargets示例)。 我有约40个不同的模型,我需要包括在我的应用程序,所以为了记忆保护的利益,我正在加载对象(和渲染纹理等)dynamic在应用程序,因为我需要他们。 我试图复制UIScrollView延迟加载的想法。 这三个4mb分配是当用户select不同的模型显示时,我已经加载到内存中的纹理。

这里有什么奇怪的东西?

仪器 - 泄漏

我对OpenGL知之甚less(我selectVurforia引擎的部分原因)。 这个屏幕下面的任何内容应该关注我吗? 请注意,Vurforia的ImageTagets示例应用程序也有未初始化的纹理数据(每帧大约一个),所以我不认为这是问题。

仪器 -  OpenGL ES分析器

任何帮助,将不胜感激!!

以下是生成3D对象的代码(在EAGLView中):

// Load the textures for use by OpenGL -(void)loadATexture:(int)texNumber { if (texNumber >= 0 && texNumber < [tempTextureList count]) { currentlyChangingTextures = YES; [textureList removeAllObjects]; [textureList addObject:[tempTextureList objectAtIndex:texNumber]]; Texture *tex = [[Texture alloc] init]; NSString *file = [textureList objectAtIndex:0]; [tex loadImage:file]; [textures replaceObjectAtIndex:texNumber withObject:tex]; [tex release]; // Remove all old textures outside of the one we're interested in and the two on either side of the picker. for (int i = 0; i < [textures count]; ++i) { if (i < targetIndex - 1 || i > targetIndex + 1) { [textures replaceObjectAtIndex:i withObject:@""]; } } // Render - Generate the OpenGL texture objects GLuint nID; Texture *texture = [textures objectAtIndex:texNumber]; glGenTextures(1, &nID); [texture setTextureID: nID]; glBindTexture(GL_TEXTURE_2D, nID); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, [texture width], [texture height], 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)[texture pngData]); // Set up objects using the above textures. Object3D *obj3D = [[Object3D alloc] init]; obj3D.numVertices = rugNumVerts; obj3D.vertices = rugVerts; obj3D.normals = rugNormals; obj3D.texCoords = rugTexCoords; obj3D.texture = [textures objectAtIndex:texNumber]; [objects3D replaceObjectAtIndex:texNumber withObject:obj3D]; [obj3D release]; // Remove all objects except the one currently visible and the ones on either side of the picker. for (int i = 0; i < [tempTextureList count]; ++i) { if (i < targetIndex - 1 || i > targetIndex + 1) { Object3D *obj3D = [[Object3D alloc] init]; [objects3D replaceObjectAtIndex:i withObject:obj3D]; [obj3D release]; } } if (QCAR::GL_20 & qUtils.QCARFlags) { [self initShaders]; } currentlyChangingTextures = NO; } 

}

这是纹理对象中的代码。

 - (id)init { self = [super init]; pngData = NULL; return self; } - (BOOL)loadImage:(NSString*)filename { BOOL ret = NO; // Build the full path of the image file NSString* resourcePath = [[NSBundle mainBundle] resourcePath]; NSString* fullPath = [resourcePath stringByAppendingPathComponent:filename]; // Create a UIImage with the contents of the file UIImage* uiImage = [UIImage imageWithContentsOfFile:fullPath]; if (uiImage) { // Get the inner CGImage from the UIImage wrapper CGImageRef cgImage = uiImage.CGImage; // Get the image size width = CGImageGetWidth(cgImage); height = CGImageGetHeight(cgImage); // Record the number of channels channels = CGImageGetBitsPerPixel(cgImage)/CGImageGetBitsPerComponent(cgImage); // Generate a CFData object from the CGImage object (a CFData object represents an area of memory) CFDataRef imageData = CGDataProviderCopyData(CGImageGetDataProvider(cgImage)); // Copy the image data for use by Open GL ret = [self copyImageDataForOpenGL: imageData]; CFRelease(imageData); } return ret; } - (void)dealloc { if (pngData) { delete[] pngData; } [super dealloc]; } @end @implementation Texture (TexturePrivateMethods) - (BOOL)copyImageDataForOpenGL:(CFDataRef)imageData { if (pngData) { delete[] pngData; } pngData = new unsigned char[width * height * channels]; const int rowSize = width * channels; const unsigned char* pixels = (unsigned char*)CFDataGetBytePtr(imageData); // Copy the row data from bottom to top for (int i = 0; i < height; ++i) { memcpy(pngData + rowSize * i, pixels + rowSize * (height - 1 - i), width * channels); } return YES; } 

可能性是,你没有看到你的应用程序真正的内存使用情况。 正如我在这个答案中解释的那样,Allocations工具隐藏了OpenGL ES中的内存使用情况,所以不能用它来衡量应用程序的大小。 相反,使用内存监视器工具,我敢打赌,将显示您的应用程序正在使用更多的内存比你想象的。 这是人们在使用仪器来优化iOS上的OpenGL ES时碰到的一个常见问题。

如果您担心哪些对象或资源可能在内存中累积,则可以使用分配工具的堆积镜头function来标识在您的应用程序中执行重复任务时分配但从未删除的特定资源。 这就是我追踪纹理和未被正确删除的其他项目。

看到一些代码将有所帮助,但我可以做一些gusses:

我有约40个不同的模型,我需要包括在我的应用程序,所以为了记忆保护的利益,我正在加载对象(和渲染纹理等)dynamic在应用程序,因为我需要他们。 我试图复制UIScrollView延迟加载的想法。 这三个4mb分配是当用户select一个不同的模型显示时,我已经加载到内存中的纹理。 (……)

这种做法并不理想, 如果内存不正确的释放,这很可能是你的问题的原因。 最后,如果你没有采取适当的预防措施,你的内存将耗尽,然后你的进程就会死亡。 所使用的引擎很可能有一些内存泄漏,由您的访问scheme暴露。

今天的操作系统不区分内存和存储。 对他们来说,这只是内存,所有的地址空间都由块存储系统支持(如果实际上有一些存储设备连接并不重要)。

所以这里是你应该做的:而不是你的模型到内存中,你应该记忆地图(mmap)。 这告诉操作系统“这部分存储应该在地址空间中可见”,操作系统内核在到期时将执行所有必要的传输。

请注意,Vurforia的ImageTagets示例应用程序也具有未初始化纹理数据(每帧大约一个),所以我不认为这是问题。

这是一个强有力的指标,OpenGL纹理对象不能正确删除。

任何帮助,将不胜感激!!

我的build议是:像1970年代那样停止编程。 今天的电脑和操作系统的工作方式不同。 另见http://www.varnish-cache.org/trac/wiki/ArchitectNotes