PDA

View Full Version : memory issues when creating a file




Chirone
Jul 20, 2009, 11:49 PM
so im exporting an image sequence as a quicktime clip and it begins to work fine.

so i think... ok let's scale this up to the whole clip!

i decide i'll use an array to act as a buffer... the array stores a number of image sequences before writing them to disk (as i'm still under the impression that this is what the code is doing)
it get's through the first couple of images fine and then it suddenly stops does nothing but it DOES tell me something that isn't the GDB disclaimer message (shock horror it the program said something useful :eek: :p)
MyProgram(1942,0xa0565720) malloc: *** mmap(size=2097152) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
so i set a break point in the method where i figure it's going wrong, and i get there and it just stops... does nothing else



int numberOfBursts = 50; // render the sequence in 50 parts
int bufferFrames = 90; // each part is 90 frames long
int i = 0;

for(i = 0; i < numberOfBursts; i++) {
// for each part...
// create a mutable array to hold all the images
NSMutableArray* imageSeq = [[NSMutableArray alloc] initWithCapacity: bufferFrames];
int j = 0;
for( j = 0; j < bufferFrames; j++) {
// for each frame that's meant to exist grab it from the current conetext
[imageSeq addObject: [self getCurrentFrame]];
<---- step forward a frame and render it to screen so then glReadPixels has something to read ------>
}
int k = 0;

for( k = 0; k < bufferFrames; k++) {
// for each image gathered..
// make a QTTime and hope like hell this is correct... because it probably isn't, even using the QTTime from existing QT files makes this cry and do something different
QTTime timeInt = QTMakeTime(1, 30);
// grab the image from the array
NSImage *img = [imageSeq objectAtIndex: k];
// add the image for (what we hope is) 1/30 of a second encoded as a png because i don't know how to change that
[mQTMovieExport addImage:img forDuration:timeInt withAttributes:attrs];
//[img release]; put this here and it will crash on the 2nd burst, it'll read from the array an NSImage but then suddenly say it's not
}
k = 0;
// release each image from memory outside that last loop because for some ********* up reason if i put in [img release] at the end of the loop above it treats future images in future bursts as something other than an image and starts to cry...
for(k = 0; k < bufferFrames; k++) {
[[imageSeq objectAtIndex: k] release];
}
// release the array
[imageSeq release];
// update the movie
[mQTMovieExport updateMovieFile];
}

i don't understand why memory is still being taken up once the j loop is done as if the images from the previous burst still exist.

if you need to know my getCurrentFrame method is the same as the third snipet from here:
http://snipt.net/Alexander_Smirnov

with a few changed before the return statement
CGImageRef imageRef = CGImageCreate(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);
NSImage* img = [[NSImage alloc] initWithData: [[[NSBitmapImageRep alloc] initWithCGImage: imageRef] TIFFRepresentation]];

free(buffer);
free(buffer2);

CFRelease(imageRef);
CFRelease(colorSpaceRef);

apologies for all the side scrolling you would have to do to give me an idea of what i'm doing wrong.

if this code that i've stated is correct and there is no reason for it to continuously take up memory when it shouldn't be then the problem must be somewhere else

please tell me what i've done is wrong



lee1210
Jul 21, 2009, 12:07 AM
A bit out of my league, but I'd change:

for(k = 0; k < bufferFrames; k++) {
[[imageSeq objectAtIndex: k] release];
}
// release the array
[imageSeq release];


To:

[imageSeq removeAllObjects];


Just take out the release of your array, and allocate it outside of the loops. When you remove all of the elements, it will be "clean" for the next go-round. From the NSMutableArray documentation:
"When an object is removed from a mutable array, it receives a release message. If there are no further references to the object, this means that the object is deallocated."

It seems like releasing the things then releasing the NSMutableArray might cause some problems. Again, i'm not very well versed in this, but that bit made me nervous.

-Lee

Chirone
Jul 21, 2009, 01:19 AM
thanks for the tip lee :)

i did try doing that after i posted, i was like "oh hey what if i try removing all items!!" but it didn't do anything :confused:
there is still something being created that isn't be deallocated..

is there a way to tell which objects are being allocated memory and if they aren't being killed when their time is up?

ChOas
Jul 21, 2009, 02:10 AM
thanks for the tip lee :)

i did try doing that after i posted, i was like "oh hey what if i try removing all items!!" but it didn't do anything :confused:
there is still something being created that isn't be deallocated..

is there a way to tell which objects are being allocated memory and if they aren't being killed when their time is up?

Try running/debugging the program with instruments.... 'leaks' should be able to tell you which objects are being leaked.

Chirone
Jul 21, 2009, 05:39 PM
i tried this

it ran with the leaks and object alloc in play and the leaks didn't show anything on the graph when the object alloc suddenly jumped...

Chirone
Jul 21, 2009, 06:42 PM
well... i commented out every line of code other than the call to [self createImage];
and it just dies faster now...
there must be something wrong with the way the NSImage is being retrieved...?

kainjow
Jul 21, 2009, 07:22 PM
Are you using the same code in that glToUIImage method you linked to? If so there are several leaks in that. Also the NSBitmapImageRep is never released. It should be autoreleased first and then have the TIFFRepresentation called. Also, converting a bitmap to a tiff is expensive. If you're targeting 10.5+ there is a direct method to create an NSBitmapImageRep from a CGImageRef.

Chirone
Jul 22, 2009, 12:02 AM
yes, i did copy the code from the posted link, but i did make changes to deal with what i thought was all the leaks, but there must be something i'm still missing...

at the guys code a bit to not be so hard coded with the width and height too:


int width = g_forcedVideoWidth;
int height = g_forcedVideoHeight;
int myDataLength = width * height * 4;

GLubyte *buffer = (GLubyte *) malloc(myDataLength);

glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);

GLubyte *buffer2 = (GLubyte *) malloc(myDataLength);

int y = 0;
for(y = 0; y < height; y++) {
int x = 0;
for(x = 0; x <width * 4; x++) {
buffer2[(height - 1 - y) * width * 4 + x] = buffer[y * 4 * width + x];
}
}

// make data provider with data.

CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer2, myDataLength, NULL);

// prep the ingredients

int bitsPerComponent = 8;

int bitsPerPixel = 32;

int bytesPerRow = 4 * width;

CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();

CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;

CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;

// make the cgimage

CGImageRef imageRef = CGImageCreate(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);

NSBitmapImageRep* bir = [[NSBitmapImageRep alloc] initWithCGImage: imageRef];
NSImage* img = [[NSImage alloc] initWithData: [bir TIFFRepresentation]];
[bir release];

free(buffer);
free(buffer2);

CFRelease( provider);
CFRelease(imageRef);
CFRelease(colorSpaceRef);

return [img autorelease];


as you can see i've added code to release the NSBitmapImageRep

I did have autorelease there too:

NSImage* img = [[NSImage alloc] initWithData: [[[[NSBitmapImageRep alloc] initWithCGImage: imageRef] autorelease] TIFFRepresentation]];

but that didn't stop the leak...

kainjow, i'm not sure which method you're mentioning, because i thought initWithCGImage did make a NSBitmapImageRep directly from a CGImageRef

kainjow
Jul 22, 2009, 11:18 AM
ah, that code is much better :)

But your TIFF conversion is unnecessary:

NSBitmapImageRep* bir = [[NSBitmapImageRep alloc] initWithCGImage: imageRef];
NSImage* img = [[NSImage alloc] initWithData: [bir TIFFRepresentation]];

Just use [img addRepresentation:bir] instead.

Chirone
Jul 22, 2009, 05:09 PM
ah ha!
it appears that the TIFFRepresentation method was the thing spiking the memory, so looping the call to getCurrentFrame no longer causes leaks

i uncommented every line of code that will add the image to the imageSeq array and add it to the QTMovie and move to the next frame. After burst 3 the program crashes, the disclaimer is printed out to the console, and for the first time ever (that i've seen) the debugger just shows a ? in the stack trace

soo.... i comment out everything and see if i can find the problem that way..

i can also add [self getCurrentImage] to the mutable array imageSeq
and remove them all without trouble

seems to be working right so far

so i take the next step and uncomment the code that adds the image to the quicktime movie and the code that updates it

seems like it'll work, the memory doesn't look like it's spiking... but there's something wrong...
the quicktime movie is coming out blank. It's just a black picture for the entire clip...


why is the image blank?