Praxiteles
Praxiteles

Reputation: 6020

How to fix this memory leak while drawing on a UIImage?

Addendum to the question below.

We have traced the growth in allocated memory to a NSMutableArray which points at a list of UIImages. The NSMutable array is in a method. It has no outside pointers, strong or weak, that are pointing at it. Because the NSMutableArray is in a method - shouldn't it - and all the objects at which it points be automatically de-allocated at some point after the method returns?

How do we ensure that happens?

=================

(1) First, does calling this code cause a memory leak or should we be looking elsewhere?

(It appears to us that this code does leak as when we look at Apple's Instruments, running this code seems to create a string of 1.19MB mallocs from CVPixelBuffer - and skipping the code avoids that. Additionally, the malloc allocation size continually creeps up across the execution cycle and never seems to be reclaimed. Adding an @autorelease pool decreased peak memory use and helped prolong the app from crashing - but there is steady increase in baseline memory use with the biggest culprit being these 1.19MB mallocs.) image2 is an existing UIImage.

image2 = [self imageByDrawingCircleOnImage:image2 withX:newX withY:newY withColor:color];

- (UIImage *)imageByDrawingCircleOnImage:(UIImage *)image withX:(int)x withY:(int)y withColor:(UIColor *)color
{
    UIGraphicsBeginImageContext(image.size);
    [image drawAtPoint:CGPointZero];
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    [color setStroke];
    CGRect shape = CGRectMake(x-10, y-10, 20, 20);
    shape = CGRectInset(shape, 0, 0);
    CGContextStrokeEllipseInRect(ctx, shape);
    UIImage *retImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return retImage;
}

(2) Second, if this code does leak, then how do we prevent the leak and, more importantly, prevent a crash from a memory shortage when we call this method multiple times in rapid succession? We notice that memory use is surging as we call this method multiple times which leads to a crash. The question is how do we ensure the rapid freeing of the discarded UIImages so that the app doesn't crash from shortage of memory while calling this method multiple times.

Upvotes: 0

Views: 455

Answers (2)

Praxiteles
Praxiteles

Reputation: 6020

We found the leak elsewhere. We needed to release a pixelBuffer. We were getting a pixelBuffer from a CGI image and adding the buffer to a AVAssetWriterInputPixelBufferAdaptor - but it was never released.

After this code which created the buffer:

    CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, 480,
                    640, kCVPixelFormatType_32ARGB, 
                    (__bridge CFDictionaryRef) options, 
                    &pxbuffer);

...and this code which appended it to an AVAssetWriter:

     [adaptor appendPixelBuffer:buffer withPresentationTime:presentTime];

...we needed to add this release code per this SO answer:

     CVPixelBufferRelease(buffer);

After that code was added, the memory footprint of the app stayed constant.

Additionally, we added @autoreleasepool { } commands to several points in the video writing code and the memory usage spikes flattened which also stabilized the app.

Our simple conclusion is that SO should get a Nobel prize.

Upvotes: 1

matt
matt

Reputation: 535119

running this code seems to create a string of 1.19MB mallocs from CVPixelBuffer

But do not make the mistake of calling memory use a memory leak. It's a leak only if the used memory can never be reclaimed. You have not proved that.

Lots of operations use memory — but that doesn't matter if the operation is performed once, because then your code ends and the memory is reclaimed.

Issues arise only if your code keeps going, possibly looping so that there is never a chance for the memory to be reclaimed; and in that situation, you can provide such a chance by wrapping each iteration of the loop in an @autoreleasepool block.

Upvotes: 2

Related Questions