renderInContext / Memory problem - memory

I have a problem. When I use the "renderInContext" in the iPad, the used memory is never released and accumulates until the application closes with "Memory Warning" Level=1 and Level=2
My code:
CGRect mediaBox = CGRectMake(0, 0, 16.54 * 72.0, 24.02 * 72.0);
CGContextRef ctx = CGPDFContextCreateWithURL((CFURLRef)[NSURL fileURLWithPath:posterPath isDirectory:NO], &mediaBox, NULL);
CGPDFContextBeginPage(ctx, NULL);
CGContextScaleCTM(ctx, 0.516, -0.516);
CGContextTranslateCTM(ctx, 0, -mediaBox.size.height - 1500);
[[self returnBigView].layer renderInContext:ctx];
CGPDFContextEndPage(ctx);
CGPDFContextClose(ctx);
CGContextRelease(ctx);
I have tried several ways, but no free memory. Any ideas?
** Sorry for my bad English

I had the same issue too, inside a loop - setting the layer contents to nil worked for me:
Releasing renderInContext result within a loop

I had the same issue. After a long investigation, it seems the memory was not released because the code did not run on the main thread. So don't execute renderInContext when you're not working on the main thread!

Related

CIImage and CIDetector use with AVCaptureOutput memory leak

I'm using a CIContext, CIDetector, and CIImage to detect rectangles in a vImage_Buffer derived from samples in captureOutput:didOutputSampleBuffer:fromConnection:. It seems that either the detector or the CIImage is retaining memory and it cannot be released.
Here is the code in question - skipping over this code shows memory held constant, otherwise in increases until crashing the app:
// ...rotatedBuf and format managed outside scope
// Use a CIDetector to find any potential subslices to process
CVPixelBufferRef cvBuffer;
vImageCVImageFormatRef cvFormat = vImageCVImageFormat_CreateWithCVPixelBuffer(pixelBuffer);
CVPixelBufferCreate(kCFAllocatorSystemDefault, rotatedBuf.width, rotatedBuf.height, kCVPixelFormatType_32BGRA, NULL, &cvBuffer);
CVPixelBufferLockBaseAddress(cvBuffer, kCVPixelBufferLock_ReadOnly);
err = vImageBuffer_CopyToCVPixelBuffer(&rotatedBuf, &format, cvBuffer, cvFormat, NULL, kvImageNoFlags);
CVPixelBufferUnlockBaseAddress(cvBuffer, kCVPixelBufferLock_ReadOnly);
if (![self vImageDidError:err]) {
CIImage *ciImage = [CIImage imageWithCVPixelBuffer:cvBuffer];
NSArray *feats = [self.ciDetector featuresInImage:ciImage options:nil];
if (feats && [feats count]) {
for (CIFeature *feat in feats) {
// The frame is currently in image space, so we must convert it to a unitless space like the other rects.
CGRect frame = feat.bounds;
CGRect clip = CGRectMake(frame.origin.x / rotatedBuf.width, frame.origin.y / rotatedBuf.height,
frame.size.width / rotatedBuf.width, frame.size.height / rotatedBuf.height);
rects = [rects arrayByAddingObject:[NSValue valueWithCGRect:clip]];
}
}
}
CVPixelBufferRelease(cvBuffer);
vImageCVImageFormat_Release(cvFormat);
Other answers seem to suggest wrapping in an autorelease pool or create a new CIDector each frame, but neither affect the memory use.
CIDetector isn't releasing memory
CIDetector won't release memory - swift
Edit: switching the dispatch queue to one other than dispatch_main_queue seemed to have cleared the memory issue and keeps the UI responsive.
I figured out a different solution - in my case I was running all my processing on the main dispatch queue. What fixed the situation was creating a new queue to run the processing in. I realized this may be the case when the majority of my CPU time was spent on the call to featuresInImage:options:. It doesn't explain what caused the memory issue, but now that I'm running in a separate queue, memory is nice and constant.

Memory Leak when create a UIImage

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;
}
}
}
Two thoughts:
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.
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).

Is this UIImage data reader thread safe?

Or this code can be executed in a background thread safely?
CGImageRef cgImage;
CGContextRef context;
CGColorSpaceRef colorSpace;
// Sets the CoreGraphic Image to work on it.
cgImage = [uiImage CGImage];
// Sets the image's size.
_width = CGImageGetWidth(cgImage);
_height = CGImageGetHeight(cgImage);
// Extracts the pixel informations and place it into the data.
colorSpace = CGColorSpaceCreateDeviceRGB();
_data = malloc(_width * _height * 4);
context = CGBitmapContextCreate(_data, _width, _height, 8, 4 * _width, colorSpace,
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);
// Adjusts position and invert the image.
// The OpenGL uses the image data upside-down compared commom image files.
CGContextTranslateCTM(context, 0, _height);
CGContextScaleCTM(context, 1.0, -1.0);
// Clears and ReDraw the image into the context.
CGContextClearRect(context, CGRectMake(0, 0, _width, _height));
CGContextDrawImage(context, CGRectMake(0, 0, _width, _height), cgImage);
// Releases the context.
CGContextRelease(context);
How to acheive the same result, if not?
(My problem is that I can't see my OpenGL textures based on the output buffer of this method, if it runs in the background)
I think you might have trouble with running this code on a separate thread from GL's like this. Even if it would work you might encounter half drawn images/textures. You could avoid this by creating a double buffer:
Your "_data" should be allocated only once and should hold 2 raw image data buffers. Then just create 2 pointers defined as foreground and background buffer (void *fg = _data[0], void *bg = _data[1] to begin with). Now when your method collects data from CGImage to bg just swap the pointers (then void *fg = _data[1], void *bg = _data[0] or the other way around)
Now your GL thread should fill your texture with data on fg (same thread as drawing).
Also you might need some locking mechanisms:
Before you push data to texture you should lock "buffer swap" and
unlock it after the push.
You will probably want to know if the
buffer has been swapped and only push fg data to texture in such
case.
Also note that if you call GL methods on more then 1 thread you will have trouble in most cases.
That looks OK to me, assuming that uiImage, _width, _height and _data aren't being manipulated from another thread at the same time. (Assuming you're using iOS 4 and above.)
Are you uploading the texture to OpenGL on the background thread? If so, that's probably the problem (since a given OpenGL context should only be accessed from a single thread at a time).
As long as you don't access UIKit (or similar frameworks) (directly or indirectly) and as long as you don't access the variables in your code from multiple threads, it's OK.

iOS leak instrument CGContextDrawPDFPage

I know this question has been asked several times, but I couldn't solve it for my particular case. CGContextDrawPDFPage is indicated as a leak in the leak instrument. Also when this segment of code is run the app crashes which I'm really sure is due to memory issues.
pdfURLDocument = [[NSURL alloc] initFileURLWithPath: [docsDir stringByAppendingPathComponent:documentName]];
pdfDocument = CGPDFDocumentCreateWithURL((CFURLRef)pdfURLDocument);
[pdfURLDocument release];
page = CGPDFDocumentGetPage(pdfDocument, 1);
CGPDFPageRetain(page);
// determine the size of the PDF page
CGRect pageRect = CGPDFPageGetBoxRect(page, kCGPDFMediaBox);
pdfScaleWidth = (1/((CGFloat) gridSizeDocument)) * self.frame.size.width/pageRect.size.width;
pdfScaleHeight = (1/((CGFloat) gridSizeDocument)) * self.frame.size.height/pageRect.size.height;
pageRect.size = CGSizeMake(pageRect.size.width*pdfScaleWidth, pageRect.size.height*pdfScaleHeight);
// Create a low res image representation of the PDF page
UIGraphicsBeginImageContext(pageRect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
// First fill the background with white.
CGContextSetRGBFillColor(context, 1.0,1.0,1.0,1.0);
CGContextFillRect(context,pageRect);
CGContextSaveGState(context);
// Flip the context so that the PDF page is rendered
// right side up.
CGContextTranslateCTM(context, 0.0, pageRect.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
// Scale the context so that the PDF page is rendered
// at the correct size for the zoom level.
CGContextScaleCTM(context, pdfScaleWidth, pdfScaleHeight);
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
CGContextSetRenderingIntent(context, kCGRenderingIntentDefault);
CGContextDrawPDFPage(context, page);
CGContextRestoreGState(context);
backgroundImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CGPDFPageRelease(page);
Also, I included CGPDFPageRelease(page); in the dealloc method. Also, it might be helpful to add that it works fine for small documents, but only crashes on large ones. Memory leaks still persist in the smaller ones, however.
I know this is an old question, but two observations:
You need to release your pdfDocument:
CGPDFDocumentRelease(pdfDocument);
You should not release the page with CGPDFPageRelease(page), though, because that is an autoreleased object and you don't own it (unless, of course, you retained it with CGPDFPageRetain).
If you use the static analyzer ("Analyze" on Xcode's "Product" menu), it should point out both of those issues.
The fundamental problem is that CGContextDrawPDFPage leaks in iOS versions prior to 6.0.
The release needs to come after the page has been used, not before. So first, move CGPDFPageRelease(page) to last in this code block and see if that helps. Also, the problem could have something to do with the CGPDFDocumentRef stored in the pdf variable. If the above doesn't help, it would be good if you show how you obtain the reference, and where you retain and release it.

UIGraphicsGetImageFromCurrentImageContext leak

I have written the following code snippet to take screen snapshot:
UIGraphicsBeginImageContext(animationView.frame.size);
[[window layer] renderInContext:UIGraphicsGetCurrentContext()];
UIImage* screenshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
But, UIGraphicsGetImageFromCurrentImageContext seems to be leaking. Is this correct?
In Instruments I could not get the exact leak point. In activity monitor I observed that when I switch to the UI that executes the above code snippet memory increments by some MB. After this point it never decreases.
Does UIGraphicsGetImageFromCurrentImageContext has memory leak? How do I solve this?
Edit
Instruments analysis
Activity Monitor: shows the memory hike when this line of code is executed; never decreases even after releasing screenshot (UIImage)
Leaks and allocation, Heap Snapshot: Does not show any leak OR this allocation.
You have just created a UIImage with data for your animationView (which could be some MB). Perhaps you should wrap this functionality in an autorelease pool.
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
UIImage* screenshot = UIGraphicsGetImageFromCurrentImageContext();
//[screenshot retain]; //If you want precise control over when it is released and you will use it later.
[pool release];
CGContextRef context = UIGraphicsGetCurrentContext();
/* you code */
CGContextRelease(context);
clear the context when done

Resources