|
Divine avenger
Join Date: Nov 2009
Location: Vic, Catalunya (Spain)
Posts: 320
|
Seems that releasing images doesn't do nothing...
Hi all!
Still battling against memory management, and after doing hundreds of tests I've found that my images' releasing methods doesn't free memory at all... I've tried loading all images just when the game starts and, after touching the screen, releasing nearly all the images and follow this with Instruments' object allocations, so I can follow how living memory goes...
What I've found is the following:
- The app starts and loads all the necessary images --> around 18 MB of used memory.
- After touching the screen, the app should releasing nearly all allocated images, so free memory is expected to increase a lot, but after touching the screen... --> around 18 MB of used memory (nearly the same). Ouch!
What happened? I'm posting how I allocate and release images:
************************************************** ************
// IMAGE ALLOCATION:
// How Images are allocated in the main function (EAGLView.m):
texTaques = [[Image alloc] initWithImage:[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"sangnormal01" ofType:@"png"]]];
// This calls an Image class' method:
----------------------------------------------------------------------------
// Image.m method:
- (id)initWithImage:(UIImage *)image {
self = [super init];
if (self != nil) {
texture = [[Texture2D alloc] initWithImage:image];
scale = 1.0f;
[self initImpl];
}
return self;
}
// And this calls a Texture2D class' method:
----------------------------------------------------------------------------
// Texture2D.m method:
- (id) initWithImage:(UIImage *)uiImage
{
NSUInteger width,
height,
i;
CGContextRef context = nil;
void* data = nil;;
CGColorSpaceRef colorSpace;
void* tempData;
unsigned int* inPixel32;
unsigned short* outPixel16;
BOOL hasAlpha;
CGImageAlphaInfo info;
CGAffineTransform transform;
CGSize imageSize;
Texture2DPixelFormat pixelFormat;
CGImageRef image;
UIImageOrientation orientation;
BOOL sizeToFit = NO;
image = [uiImage CGImage];
orientation = [uiImage imageOrientation];
if(image == NULL) {
[self release];
NSLog(@"Image is Null");
return nil;
}
info = CGImageGetAlphaInfo(image);
hasAlpha = ((info == kCGImageAlphaPremultipliedLast) || (info == kCGImageAlphaPremultipliedFirst) || (info == kCGImageAlphaLast) || (info == kCGImageAlphaFirst) ? YES : NO);
if(CGImageGetColorSpace(image)) {
if(hasAlpha)
pixelFormat = kTexture2DPixelFormat_RGBA8888;
else
pixelFormat = kTexture2DPixelFormat_RGB565;
//pixelFormat = kTexture2DPixelFormat_RGBA8888;
} else //NOTE: No colorspace means a mask image
pixelFormat = kTexture2DPixelFormat_A8;
imageSize = CGSizeMake(CGImageGetWidth(image), CGImageGetHeight(image));
transform = CGAffineTransformIdentity;
width = imageSize.width;
if((width != 1) && (width & (width - 1))) {
i = 1;
while((sizeToFit ? 2 * i : i) < width)
i *= 2;
width = i;
}
height = imageSize.height;
if((height != 1) && (height & (height - 1))) {
i = 1;
while((sizeToFit ? 2 * i : i) < height)
i *= 2;
height = i;
}
while((width > kMaxTextureSize) || (height > kMaxTextureSize)) {
width /= 2;
height /= 2;
transform = CGAffineTransformScale(transform, 0.5, 0.5);
imageSize.width *= 0.5;
imageSize.height *= 0.5;
}
switch(pixelFormat) {
case kTexture2DPixelFormat_RGBA8888:
colorSpace = CGColorSpaceCreateDeviceRGB();
data = malloc(height * width * 4);
context = CGBitmapContextCreate(data, width, height, 8, 4 * width, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);
break;
case kTexture2DPixelFormat_RGB565:
colorSpace = CGColorSpaceCreateDeviceRGB();
data = malloc(height * width * 4);
context = CGBitmapContextCreate(data, width, height, 8, 4 * width, colorSpace, kCGImageAlphaNoneSkipLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);
break;
case kTexture2DPixelFormat_A8:
data = malloc(height * width);
context = CGBitmapContextCreate(data, width, height, 8, width, NULL, kCGImageAlphaOnly);
break;
default:
[NSException raise:NSInternalInconsistencyException format:@"Invalid pixel format"];
}
CGContextClearRect(context, CGRectMake(0, 0, width, height));
CGContextTranslateCTM(context, 0, height - imageSize.height);
if(!CGAffineTransformIsIdentity(transform))
CGContextConcatCTM(context, transform);
CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image)), image);
//Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRGGGGGGBBBBB"
if(pixelFormat == kTexture2DPixelFormat_RGB565) {
tempData = malloc(height * width * 2);
inPixel32 = (unsigned int*)data;
outPixel16 = (unsigned short*)tempData;
for(i = 0; i < width * height; ++i, ++inPixel32)
*outPixel16++ = ((((*inPixel32 >> 0) & 0xFF) >> 3) << 11) | ((((*inPixel32 >> 8) & 0xFF) >> 2) << 5) | ((((*inPixel32 >> 16) & 0xFF) >> 3) << 0);
free(data);
data = tempData;
}
self = [self initWithData:data pixelFormat:pixelFormat pixelsWide:width pixelsHigh:height contentSize:imageSize];
CGContextRelease(context);
free(data);
return self;
}
- (id) initWithData:(const void*)data pixelFormat:(Texture2DPixelFormat)pixelFormat pixelsWide:(NSUInteger)width pixelsHigh:(NSUInteger)height contentSize:(CGSize)size
{
GLint saveName;
if((self = [super init])) {
glGenTextures(1, &_name);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &saveName);
glBindTexture(GL_TEXTURE_2D, _name);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
switch(pixelFormat) {
case kTexture2DPixelFormat_RGBA8888:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
break;
case kTexture2DPixelFormat_RGB565:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data);
break;
case kTexture2DPixelFormat_A8:
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, data);
break;
default:
[NSException raise:NSInternalInconsistencyException format:@""];
}
glBindTexture(GL_TEXTURE_2D, saveName);
_size = size;
_width = width;
_height = height;
_format = pixelFormat;
_maxS = size.width / (float)width;
_maxT = size.height / (float)height;
}
return self;
}
************************************************** ************
// ONCE THIS IS DONE, TIME TO FOLLOW THE RELEASING METHODS:
// How images are released in the main method:
[texTaques release];
// This should call the Image.m release method:
----------------------------------------------------------------------------
// Image.m method:
- (void) dealloc
{
//NSLog(@"RELEASE Image");
// texture is a Texture2D object, so this will call the Texture2D dealloc method
[texture release];
[super dealloc];
}
----------------------------------------------------------------------------
// Texture2D.m (which inherits from NSObject) method:
- (void) dealloc
{
//NSLog(@"RELEASE Texture2D");
[super dealloc];
}
************************************************** ************
I've expected this should work, but when release is called no memory is freed at all, so seems that something is going really wrong...
Any idea about this? Any help will be appreciated, really!
Thanks in advance.
|