views:

255

answers:

2

When converting PDF Pages into UIImages I receive memory warnings all the time.

It seems there is either some leak or something else that eats my memory.

Using instruments didn't give me any helpful details.

I'm using the following function to generate images from a pdf file:

- (UIImage*)pdfImage:(NSString*)pdfFilename page:(int)page {

 CFURLRef pdfURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, (CFStringRef)pdfFilename, kCFURLPOSIXPathStyle, false);
 CGPDFDocumentRef pdfRef = CGPDFDocumentCreateWithURL((CFURLRef)pdfURL);
 CFRelease(pdfURL);

 CGPDFPageRef pdfPage = CGPDFDocumentGetPage(pdfRef, page);
 CGRect pdfPageSize = CGPDFPageGetBoxRect(pdfPage, kCGPDFBleedBox);

 float pdfScale;
 if ( pdfPageSize.size.width < pdfPageSize.size.height ) {
  pdfScale = PDF_MIN_SIZE / pdfPageSize.size.width;
 }
 else {
  pdfScale = PDF_MIN_SIZE / pdfPageSize.size.height;
 }


 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
 CGContextRef context = CGBitmapContextCreate(NULL, 
             pdfPageSize.size.width*pdfScale,
             pdfPageSize.size.height*pdfScale,
             8,
             (int)pdfPageSize.size.width*pdfScale * 4,
             colorSpace, 
             kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
 CGColorSpaceRelease(colorSpace);
 // CGContextClipToRect(context, pdfPageView.frame);

// CGPDFPageRetain(pdfPage);
 CGAffineTransform transform = aspectFit(CGPDFPageGetBoxRect(pdfPage, kCGPDFBleedBox),
             CGContextGetClipBoundingBox(context));
 CGContextConcatCTM(context, transform);
 CGContextDrawPDFPage(context, pdfPage);
// CGPDFPageRelease (pdfPage);

 CGImageRef image = CGBitmapContextCreateImage(context);
 CGContextRelease(context);

 UIImage *finalImage = [UIImage imageWithCGImage:image];
 CGImageRelease(image);
 CGPDFDocumentRelease(pdfRef);


 return finalImage;
}

I am releasing the document and everything else, so where could be the problem?

Thanks for your help!

+1  A: 

Leaks does sometimes give false positives or may even be reporting leaks that are not in your code. What does the analyzer (shift-option-A) say? I would trust it first. Another thing to check is whether your leak problem goes away with a move to a new version of the simulator.

Adam Eberbach
The leak occurs on the device (using os 3.2) itself, not the simulator.I somehow cannot analyze the classe because it is skipped because of a parse error because I declared variables inside the interface ( "cannot declare variable insode @interface or @protocol" ).
favo
I'd take the variables out of the interface. The analyzer is worth a bit of reorganization.
Adam Eberbach
I've did that and played a bit with the analyzer. Your right, its absolutely worth the reorganization! But it does not give me any help for this problem. I received possible leaks in other places but nothing in the code sequence I've posted and that causes the problems.
favo
Thank you Adam! I have found the problem using the analyzer and some testing. Adding an "autorelease" to a returning UIImage in a function did the real job :-)
favo
+2  A: 

Well, everytime you call this method, assuming you keep the result around, the autoreleased object allocated in

UIImage *finalImage = [UIImage imageWithCGImage:image];

will consume some memory. The iPhone is pretty unforgiving, so if you have a few of these images (or even just one), and some reasonably large pdf's, you could hit the memory limit pretty easily.

I've just been working with a 3000 x 2000 pixel image, and hit memory warnings all the time, until I started tiling it.

So,

1) how large are your pdf's pages?

2) are you keeping them around?

3) If you comment out the line mentioned above, and just return nil instead, do you still hit the memory warnings?

Snydely Whiplash
I'm adding pages generated thru this function to a UIScrollView updating it with UIImageViews whenever a new PDF is loaded.Changing it to return nil seems solved the problem.releasing the returned image in the function that calls that function using:UIImage *tstImg = [self pdfImage:filename page:1];UIImageView *tstView = [[UIImageView alloc] initWithImage: tstImg];[..][tstImg release];.. gets me errors of messages sent to a deallocated instance.If this is the memory problem, how should I release the object correctly, if it is not autoreleased and manual release leads to errors?
favo
The PDF files are about 1024x768 pixels, displaying 1-6 pages at a time.
favo
I would try keeping fewer pages around. Maybe the current, next, and previous. If producing them takes a while, then you could try caching them on disk, instead of in memory.Re: your release issue above, you don't need to release tstImg in the case you cite, as its marked for autorelease when it gets returned from the pdfImage:page: method, and it will be retained by the imageview.That release will probably cause it to be dealloced, leaving the imageview holding garbage, and a crash waiting to happen.When you release the image view, it will get cleaned up properly - snydely_whiplash
Snydely Whiplash
In most cases I'm only displaying a single page. Generating a new UIImage from the same pdf page repeatingly causes the same issues.
favo