I am using objective C in a c++ application to load images on OSX. It is an OpenGL application. This is the code I use to load an image into 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;
}
Thanks to Instruments I have detected a memory leak every time this function is called. Instruments says [NSImage TIFFRepresentation]
and [NSBitmapImageRep bitmapData]
are using up a huge amount of memory.
It does not climb out of control but everytime this function is called the memory usage climbs a few hundred kilobytes.
My experience with objective-c is limited and so I do not know how to fix this as I thought release
would work fine.
Just so you know the OpenGL texture is freed at a later point and I have confirmed it is not the source of the memory leak.
EDIT: After some further testing I have discovered this is not theoretically a memory leak as Instruments is not reporting a "memory leak" as such. But whenever this function is called the memory usage of the application goes up and never comes down. This function is called when scenes in the game are loaded, and so whenever a scene is loaded memory usage goes up several megabytes. How could this possibly be happening. I am sure it is this function that is using up all the memory.
First off: The code doesn't look like it is leaking. My guess is that NSImage is doing some harmless caching internally that ensures it can re-use the same NSImage if you ever load this image file a second time, and that's maybe what you're seeing. Or maybe it's the file system cache. If memory gets tight, these caches will probably get flushed and the freed memory becomes available to your application.
That said, your code seems overly complicated. You create an NSImage (which consists of NSImageReps, one of which is very likely an NSBitmapImageRep) then get its TIFFRepresentation (i.e. re-encode all that data to TIFF, possibly compressing it again), then create an NSBitmapImageRep from that (decompressing and decoding the TIFF again), and then getting its bitmapData.
At the least, you should probably create an NSData from the file and create your NSBitmapImageRep from that. That will skip the entire NSImage creation and TIFF steps.
Even better would probably be if you just went and used the lower-level ImageIO library. Create a CGImageRef from your file, then hand the image's raw, decompressed data off to OpenGL. I vaguely remember there might even be a better way to create an OpenGL texture if you go through CIImage or CoreVideo, but I may be mixing that up with the reverse (texture to CIImage).