0

I have following method to take a pdf file in documents directory and create a thumbnail out of it. This method is leaking memory in two places as shown in comments. Since I am using ARC I am not sure why is it leaking memory. How can I solve this.

  + (UIImage*)createPdfThumbnail:(NSString*)pdfFilePath {


        NSURL *targetURL = [NSURL fileURLWithPath:pdfFilePath];
        CGPDFDocumentRef pdf = CGPDFDocumentCreateWithURL((__bridge CFURLRef)targetURL);  // 3.0% of memory leak

        CGPDFPageRef page = CGPDFDocumentGetPage(pdf, 1);//for the first  page
        CGRect aRect = CGPDFPageGetBoxRect(page, kCGPDFCropBox);
        UIGraphicsBeginImageContext(aRect.size);
        CGContextRef context = UIGraphicsGetCurrentContext();

        CGContextSaveGState(context);
        CGContextTranslateCTM(context, 0.0, aRect.size.height);
        CGContextScaleCTM(context, 1.0, -1.0);
        CGContextTranslateCTM(context, -(aRect.origin.x), -(aRect.origin.y));

        CGContextSetGrayFillColor(context, 1.0, 1.0);
        CGContextFillRect(context, aRect);

        CGAffineTransform pdfTransform = CGPDFPageGetDrawingTransform(page, kCGPDFCropBox, aRect, 0, false);
        CGContextConcatCTM(context, pdfTransform);
        CGContextDrawPDFPage(context, page);

        UIImage *thumbnail = UIGraphicsGetImageFromCurrentImageContext(); // 97% of memory leak
        CGContextRestoreGState(context);
        UIGraphicsEndImageContext();
        CGPDFDocumentRelease(pdf);
        return thumbnail;

}

EDIT:

-(void)fromJSON:(NSDictionary *)JSON{
    [super fromJSON:JSON];
    self.path = JSON[@"path"];
    //Create and save thumbnail
    if (self.parentSpecSheet != nil){
        @autoreleasepool {
            UIImage* thumbnail = [Utilities createPdfThumbnail:self.path];
            Photo* thumbnailPhoto = [Photo addObject];
            [thumbnailPhoto setDelta:@(0)];
            [thumbnailPhoto setImage:thumbnail];
            [thumbnailPhoto.file setDelta:@(0)];
            self.parentSpecSheet.thumbnail = thumbnailPhoto;
        }
    }
}
ila
  • 920
  • 12
  • 35

1 Answers1

0

Two thoughts:

  1. I experience a significant leak from CGContextDrawPDFPage when I test your code in iOS5 (and if you search for "CGContextDrawPDFPage leak", you'll see tons of references to permutations of this problem). This appears to be a known problem.

    I see no appreciable leak in iOS 6 from the above code, though.

  2. If you're still seeing this leak in iOS 6, then I suspect the problem does not rest in the above code. Do you have any other leaks reported? I'd also suggest you confirm that the object that owns this thumbnail is successfully getting deallocated itself (e.g. log/breakpoint in its dealloc method).

    Unfortunately, when you look at the leaks tool, it's reporting where the leaked object was instantiated, not where the leak took place. You might want to confirm that the owner of this thumbnail is not, somehow, maintaining a strong reference to it (e.g., the owner, itself, has a retain cycle, or something like that).

Community
  • 1
  • 1
Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • Hi Rob, thanks for your help, I am running this in iOS 5.1 , I have added the code that is calling this method. I am running both these functions in background thread – ila Jul 17 '13 at 08:27
  • @ila I think this is an iOS 5 bug, since fixed in iOS 6. See http://stackoverflow.com/questions/14141423/cgcontextdrawpdfpage-leaking-in-ios-6 for some potential workarounds that might work for iOS 5 (though I cannot attest to them). For me the question is how much effort would I invest in a iOS 5 bug given the high iOS 6 conversion rate (I might be inclined to still support iOS 5 target, but maybe put in a runtime iOS version check that doesn't generate the custom thumbnail for devices running iOS versions prior to 6.0). Just a question of how much time to invest in a bug in old iOS version. – Rob Jul 17 '13 at 14:17
  • Even in i0S 6 it leaking memory. – ila Jul 19 '13 at 03:33
  • @ila When I run this code, I see modest increase in allocations in 6.0 and greater (but huge leaks in 5.0, though). I'm a little surprised you're not seeing differences b/w 5.x behavior and 6.x. It was significant for me. Regardless, if you're really getting the leaked message at the `UIGraphicsGetImageFromCurrentImageContext` line from Leaks tool, that means that the image, itself is leaking. Thus, this code is not the cause of the leak, but rather Leaks is just letting you know where the leaked object was created. See second point of my original answer for additional suggestions. – Rob Jul 19 '13 at 03:50