PDA

View Full Version : CGContextRef and Pointers. Memory management problem




Hijacker
Apr 25, 2009, 03:58 AM
Hi everybody, I'm trying to get something to work properly for about 2 days but it's beyond me. So my problem is this:

I have a function that has to update a pointer with the content of a CGImageRef which is constantly changing (or almost constantly). The problem is that when I update this pointer I get more and more memory allocated and whatever I tried is not freeing up the memory, I will list the two methods that cause this huge object allocation and than try to explain my problem a little more. Below you have the method that updates my pointer with the new BitmapData, the struct that represents a pixel and the method that creates a BitmapDataContext:




//THIS IS THE STRUCT USED FOR A PIXEL REPRESENTATION
typedef struct {
Byte alpha;
Byte red;
Byte green;
Byte blue;
} Pixel;

//THIS IS THE POINTER I USE TO MANIPULATE IMAGE PIXELS AND I THINK THIS LOADS THE MEMORY
Pixel *mapData;


- (void) updateMapImage:(CGImageRef)mapImage{

if(mapData){

free(mapData); //HERE I'M TRYING TO RELEASE THE OLD POINTER DATA
mapData = NULL;
}

//I CREATE THEN A NEW BITMAPCONTEXT WITH THE NEW IMAGE
CGContextRef cgctx = [self CreateARGBBitmapContext:mapImage];

if(cgctx == NULL) {
NSLog(@"Error creating context");

}

mapWidth = CGImageGetWidth(mapImage);
mapHeight = CGImageGetHeight(mapImage);
CGRect rect = CGRectMake(0,0,mapWidth,mapHeight);


CGContextDrawImage(cgctx, rect, mapImage);

//GET THE NEW DATA OUT FROM THE BITMAP CONTEXT
Byte *mapDataBytes =(Byte *)CGBitmapContextGetData(cgctx);

if (mapDataBytes != NULL){

//REPOPULATE MY DATA POINTER
mapData = malloc(mapWidth * mapHeight * sizeof(Pixel));


for(int y = 0; y < mapHeight; y++){
for(int x = 0; x < mapWidth; x++){
mapData[y * mapWidth + x].alpha = (Byte)mapDataBytes[0];
mapData[y * mapWidth + x].red = (Byte)mapDataBytes[1];
mapData[y * mapWidth + x].green = (Byte)mapDataBytes[2];
mapData[y * mapWidth + x].blue = (Byte)mapDataBytes[3];
mapDataBytes += 4;
}
}

}


free(mapDataBytes);
mapDataBytes = NULL;

CGContextRelease(cgctx);

}



//THIS IS THE METHOD THAT CREATES MY BITMAPCONTEXT FROM INPUT IMAGE
- (CGContextRef) CreateARGBBitmapContext:(CGImageRef) inImage{
CGContextRef context = NULL;
CGColorSpaceRef colorSpace;
void * bitmapData;
int bitmapByteCount;
int bitmapBytesPerRow;

size_t pixelsWide = CGImageGetWidth(inImage);
size_t pixelsHigh = CGImageGetHeight(inImage);

bitmapBytesPerRow = (pixelsWide * 4);
bitmapByteCount = (bitmapBytesPerRow * pixelsHigh);


colorSpace = CGColorSpaceCreateDeviceRGB();
if (colorSpace == NULL){
NSLog(@"Error allocating color space");
return NULL;
}

bitmapData = malloc( bitmapByteCount );
if (bitmapData == NULL){
NSLog(@"Memory not allocated");
CGColorSpaceRelease(colorSpace);
return NULL;
}

context = CGBitmapContextCreate ( bitmapData,
pixelsWide,
pixelsHigh,
8,
bitmapBytesPerRow,
colorSpace,
kCGImageAlphaPremultipliedFirst );
if (context == NULL){
free(bitmapData);
NSLog(@"Context not created!");
}

CGColorSpaceRelease( colorSpace );

return context;

}



As you can see I tried to deallocate the pointer and release the context every time I update but It seems I do something wrong because memory gets allocated more and more until my app crashes. I hope someone around this forum cand point me in a right direction because I'm out of clues.
Thanks in advance for your time and your help.

P.S.: I apologize for my rusty english.



BlackWolf
Apr 25, 2009, 05:20 AM
this isn't really objective-c, is it?

Hijacker
Apr 25, 2009, 05:35 AM
this isn't really objective-c, is it?

I don't think I understand your question. Those CG* methods are Quartz2D primitives, part of iPhoneSDK and I use this code to manipulate a UIImage* . Please be more specific, what is wrong with the way I wrote the code? I'm new to xCode and ObjC and any advice is appreciated.

BlackWolf
Apr 25, 2009, 06:10 AM
I don't think I understand your question. Those CG* methods are Quartz2D primitives, part of iPhoneSDK and I use this code to manipulate a UIImage* . Please be more specific, what is wrong with the way I wrote the code? I'm new to xCode and ObjC and any advice is appreciated.

well, I can't really help you with your problem since I didn't use quartz2D stuff until now, but it seems to me like your code is more c++ or something like it is objective-c, and I guess that could maybe be a problem when people want to help you ... but I could be wrong :D
for example
free(mapData);
is not really objective-c, if it does what I think it does it would be
[mapData release];
in objC ... I guess maybe that could have something to do with your problem.

Hijacker
Apr 25, 2009, 06:21 AM
well, I can't really help you with your problem since I didn't use quartz2D stuff until now, but it seems to me like your code is more c++ or something like it is objective-c, and I guess that could maybe be a problem when people want to help you ... but I could be wrong :D
for example
free(mapData);
is not really objective-c, if it does what I think it does it would be
[mapData release];
in objC ... I guess maybe that could have something to do with your problem.

Oh that's what you were talking about. Well as far as i've seen iPhone programming mixes old C syntax with ObjC syntax at least when you want to integrate graphics libraries (OpenGL, CG). I may be wrong but i've seen this mix of syntax in books as well so I don't think you can only stick with objC syntax if you embed other libraries in your app.

PhoneyDeveloper
Apr 25, 2009, 09:31 AM
I don't really see anything wrong in the code that you show. You do know that you don't have to pre-allocate the data block for CGContextBitmapCreate(), right? You can just pass null and then the system will create and manage that block.

At any rate, what kind of memory does ObjectAlloc show as being leaked or ever increasing?

kainjow
Apr 25, 2009, 12:45 PM
well, I can't really help you with your problem since I didn't use quartz2D stuff until now, but it seems to me like your code is more c++ or something like it is objective-c, and I guess that could maybe be a problem when people want to help you ... but I could be wrong :D
for example
free(mapData);
is not really objective-c, if it does what I think it does it would be
[mapData release];
in objC ... I guess maybe that could have something to do with your problem.

Objective-C is a superset of C. Meaning, Objective-C is C, but with extensions to support OOP. So everything that can be done in C can be done in Objective-C.

Most of what you think is Objective-C is just ordinary C :)

eddietr
Apr 25, 2009, 01:29 PM
It looks to me that you are not freeing the bitmap data. By the time you call...


free(mapDataBytes);


... you have already advanced mapDataBytes past the buffer.

Guiyon
Apr 25, 2009, 02:16 PM
It looks like eddietr's got it! In order for 'free' to work properly, it needs to be passed a pointer to the beginning of the block m/calloc allocated. Inside your loop you are using
mapDataBytes += 4;
which is incrementing the pointer loop which means, by the end of the loop, you're pointing at someone else's memory and trying to free it. In the best case, nothing happens but I'm surprised that you aren't hitting a SEGFAULT there...

firewood
Apr 25, 2009, 02:21 PM
it seems to me like your code is more c++ or something like it is objective-c, and I guess that could maybe be a problem when people want to help you

Pure Nonsense.

Huge portions of the iPhone Mac OS X API's are in plain C. And a large number of the better iPhone programmers are competent C or C++ programmers. You can write a large robust iPhone app (Wolfenstein, for instance), using only a couple pages of Obj-C to hook up the UI to a C application.

Hijacker
Apr 25, 2009, 06:28 PM
It looks to me that you are not freeing the bitmap data. By the time you call...


free(mapDataBytes);


... you have already advanced mapDataBytes past the buffer.

It looks like eddietr's got it! In order for 'free' to work properly, it needs to be passed a pointer to the beginning of the block m/calloc allocated. Inside your loop you are using

Code:
mapDataBytes += 4;which is incrementing the pointer loop which means, by the end of the loop, you're pointing at someone else's memory and trying to free it. In the best case, nothing happens but I'm surprised that you aren't hitting a SEGFAULT there...

Thanks a lot! That was the problem, it is solved now so i'll post the correct part of code that was wrong maybe it will help others.


int i=0;
for(int y = 0; y < mapHeight; y++){
for(int x = 0; x < mapWidth; x++, i += 4){
mapData[y * mapWidth + x].alpha = (Byte)mapDataBytes[i];
mapData[y * mapWidth + x].red = (Byte)mapDataBytes[i + 1];
mapData[y * mapWidth + x].green = (Byte)mapDataBytes[i + 2];
mapData[y * mapWidth + x].blue = (Byte)mapDataBytes[i + 3];
}
}


So once again, thank you!