c++ - NSImage 和 NSBitmapImageRep 内存泄漏

标签 c++ objective-c appkit nsimage

我在 C++ 应用程序中使用 Objective-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,每次调用此函数时我都检测到内存泄漏。 Instruments 表示 [NSImage TIFFRepresentation][NSBitmapImageRep bitmapData] 正在占用大量内存。

它并没有失控,但每次调用此函数时,内存使用量都会攀升数百 KB。

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

只是想让你知道 OpenGL 纹理稍后会被释放,我已经确认它不是内存泄漏的根源。

编辑:经过一些进一步的测试,我发现这在理论上不是内存泄漏,因为 Instruments 没有报告这样的“内存泄漏”。但是每当调用此函数时,应用程序的内存使用量都会上升并且永远不会下降。当加载游戏中的场景时调用此函数,因此每当加载场景时,内存使用量都会增加几兆字节。这怎么可能发生。我确定是这个函数用完了所有内存。

最佳答案

首先:代码看起来没有泄漏。我的猜测是 NSImage 正在内部进行一些无害的缓存,以确保它可以在您第二次加载此图像文件时重新使用相同的 NSImage,这可能就是您所看到的。或者可能是文件系统缓存。如果内存紧张,这些缓存可能会被刷新,释放的内存可供您的应用程序使用。

也就是说,您的代码似乎过于复杂。您创建一个 NSImage(由 NSImageReps 组成,其中一个很可能是 NSBitmapImageRep)然后获取其 TIFFRepresentation(即将所有数据重新编码为 TIFF,可能再次压缩),然后从中创建一个 NSBitmapImageRep(解压缩和解码) TIFF),然后获取其位图数据。

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

如果您只是去使用较低级别的 ImageIO 库,可能会更好。从您的文件创建一个 CGImageRef,然后将图像的原始解压缩数据交给 OpenGL。我依稀记得如果你通过 CIImage 或 CoreVideo 甚至可能有更好的方法来创建 OpenGL 纹理,但我可能会把它与相反的方式(纹理到 CIImage)混为一谈。

关于c++ - NSImage 和 NSBitmapImageRep 内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12920937/

相关文章:

ios - swift框架中使用modulemap桥接OC,project中报缺少所需模块

macos - 如何在WKWebView上设置内容和滚动插图?

c++ - 函数级静态变量何时分配/初始化?

c++ - 确保函数在lock_guard下运行

c++ - 用于极端图像缩小的快速、高质量像素插值

ios - 如何在 iPhone 应用程序中播放 SWF 文件

iphone - 如果手机未连接到互联网,请加载不同的 Nib

c++ - Linux (g++) 上出现段错误,但 Mac OS 上却没有。?

macos - WKWebView 从一开始就没有在 NSViewRepresentable 中显示

macos - 将搜索框置于标题栏左侧