NSImage和NSBitmapImageRep内存泄漏

时间:2012-10-16 18:16:33

标签: c++ objective-c appkit nsimage

我在c ++应用程序中使用目标C来在OSX上加载图像。它是一个OpenGL应用程序。这是我用来将图像加载到opengl中的代码:

bool OSXSpecifics::loadPNGOSX(const char *fileName, int &outWidth, int &outHeight, GLuint *outTexture) {
NSImage *image = [[NSImage alloc] initWithContentsOfFile:[NSString stringWithUTF8String: fileName]];
NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithData:[image TIFFRepresentation]];

NSArray* imageReps = [image representations];

bool hasAlpha;

for (NSImageRep *imageRep in imageReps) {
    if ([imageRep pixelsHigh] > outHeight) {
        outHeight = [imageRep pixelsHigh];
    }
    if ([imageRep pixelsWide] > outWidth) {
        outWidth = [imageRep pixelsWide];
    }
}
if ([bitmap hasAlpha] == YES) {
    hasAlpha = true;
} else {
    hasAlpha = false;
}


glGenTextures(1, outTexture);
glBindTexture(GL_TEXTURE_2D, *outTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

glTexImage2D(GL_TEXTURE_2D, 0, hasAlpha ? 4 : 3, outWidth, outHeight, 0,
             hasAlpha ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, [bitmap bitmapData]);
[bitmap release];
[image release];
return true;
}

感谢Instruments,每次调用此函数时都会检测到内存泄漏。乐器说[NSImage TIFFRepresentation][NSBitmapImageRep bitmapData]占用了大量的内存。

它不会失控,但每次调用此函数时,内存使用量都会攀升几百千字节。

我对objective-c的体验有限,所以我不知道如何解决这个问题,因为我认为release可以正常工作。

您知道稍后会释放OpenGL纹理,并且我已经确认它不是内存泄漏的来源。

编辑:经过一些进一步的测试后,我发现这不是理论上的内存泄漏,因为Instruments没有报告“内存泄漏”。但是无论什么时候调用这个函数,应用程序的内存使用率都会上升而且永远不会降低。加载游戏中的场景时会调用此函数,因此无论何时加载场景,内存使用量都会增加几兆字节。怎么可能发生这种情况。我确信这个功能耗尽了所有内存。

1 个答案:

答案 0 :(得分:1)

首先关闭:代码看起来不像是泄漏。我的猜测是NSImage在内部进行一些无害的缓存,确保它可以重新使用相同的NSImage,如果你再次加载这个图像文件,那也许就是你所看到的。或者也许是文件系统缓存。如果内存变紧,这些缓存可能会被刷新,并且释放的内存可供您的应用程序使用。

那就是说,你的代码看起来过于复杂。你创建一个NSImage(由NSImageReps组成,其中一个非常可能是NSBitmapImageRep)然后得到它的TIFFRepresentation(即将所有数据重新编码为TIFF,可能再次压缩它),然后从中创建一个NSBitmapImageRep(解压缩和解码)再次获得TIFF),然后得到它的bitmapData。

至少,你应该从文件创建一个NSData并从中创建NSBitmapImageRep。这将跳过整个NSImage创建和TIFF步骤。

如果您刚刚使用较低级别的ImageIO库,可能会更好。从您的文件创建CGImageRef,然后将图像的原始解压缩数据移交给OpenGL。我依稀记得如果你通过CIImage或CoreVideo,甚至可能有更好的方法来创建OpenGL纹理,但我可能会将其与反向(纹理到CIImage)混合起来。