0

I am loading images from disk, converting them to CVPixelBufferRef, doing some stuff, then converting back to UIImage to save back to disk. I have tried to make sure I release absolutely everything necessary, yet memory usage for my app always increases until it crashes.

for (//iterate through images) {
    CVPixelBufferRef pixelBuffer = [self pixelBufferFromCGImage:image.CGImage];
    // do some stuff
    UIImage *newImage = [self imageFromPixelBuffer:pixelBuffer];
    CVPixelBufferRelease(pixelBuffer);
}

Here are the two methods I use:

- (CVPixelBufferRef)pixelBufferFromCGImage:(CGImageRef)image {

    CGSize frameSize = CGSizeMake(CGImageGetWidth(image), CGImageGetHeight(image));
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey, [NSNumber numberWithBool:YES],kCVPixelBufferCGBitmapContextCompatibilityKey, nil];
    CVPixelBufferRef pxbuffer = NULL;

    CVReturn status = CVPixelBufferCreate(
                        kCFAllocatorDefault, frameSize.width, frameSize.height,
                        kCVPixelFormatType_32BGRA, (__bridge CFDictionaryRef)options,
                        &pxbuffer);
    NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL);

    CVPixelBufferLockBaseAddress(pxbuffer, 0);
    void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);

    CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(
                                                 pxdata, frameSize.width, frameSize.height,
                                                 8, CVPixelBufferGetBytesPerRow(pxbuffer),
                                                 rgbColorSpace,
                                                 (CGBitmapInfo)kCGBitmapByteOrder32Little |
                                                 kCGImageAlphaPremultipliedFirst);

    CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image),
                                           CGImageGetHeight(image)), image);
    CGColorSpaceRelease(rgbColorSpace);
    CGContextRelease(context);

    CVPixelBufferUnlockBaseAddress(pxbuffer, 0);

    CGImageRelease(image);

    return pxbuffer;
}

- (UIImage *)imageFromPixelBuffer:(CVPixelBufferRef)pixelBuffer {
    CIImage *ciImage = [CIImage imageWithCVPixelBuffer:pixelBuffer];
    CIContext *context = [CIContext contextWithOptions:nil];
    CGImageRef myImage = [context createCGImage:ciImage fromRect:CGRectMake(0, 0, CVPixelBufferGetWidth(pixelBuffer), CVPixelBufferGetHeight(pixelBuffer))];
    UIImage *image = [UIImage imageWithCGImage:myImage];

    CGImageRelease(myImage);

    return image;
}

In the real application, of course I don't just save the exact same image, but create new pixel buffers from the first one, and then save all those images. However, the memory increase problem is present even for this trivial example.

I must be missing something elementary, this is driving me nuts.

Maxi Mus
  • 795
  • 1
  • 6
  • 20

2 Answers2

0

Build and open your app in Instruments, choose the Leaks instrument, and exercise your app.

It will show you any memory leaks which you can then track down.

If there are in fact NO leaks, then you've got a more subtle problem. Run the Allocations instrument, exercise your app, and (from what you're describing) you'll see a gradual ramp. Select a region of the ramp and inspect all the new allocations -- you will start to see patterns -- groups of similar appearing allocations. These will give you clues as to where exactly in the code the unreleased allocation is happening.

joeybladb
  • 227
  • 1
  • 10
  • And then shout out "doh!" when you've spotted the problem. – joeybladb Jan 12 '17 at 23:59
  • Thanks. I really have to start learning the instruments. However, this doesn't really help me either. My code is extremely simple, It seems to me anyone even slightly experienced with CV or CG classes should be immediately able to spot the culprit - unless releasing some kind of memory is not the issue in the first place. – Maxi Mus Jan 13 '17 at 02:43
  • That's the problem -- I can't see anything wrong with the code. Admittedly I haven't used CoreVideo in about 5 years so I forget all the allocation rules. Also, it's never the wrong time to learn how to use Instruments. Seriously, it's an incredibly powerful tool. You'll debug problems like this one in 5 minutes. – joeybladb Jan 13 '17 at 07:27
-1

Remove CGImageRelease(image) line. You are only referencing using image.CGImage as a argument for pixelBufferFromCGImage:. So you are not creating, retaining it, so it is not your responsibility to release it.

  • Also look at [Link 1](http://stackoverflow.com/questions/4567465/cgimageref-memory-leak) and [Link 2](http://stackoverflow.com/questions/9574785/cgimagerelease-not-a-type-release-message-sent-to-deallocated-instance) – Gor Baghdasaryan Jan 12 '17 at 19:56
  • Thanks, but that cannot possibly be the solution. I only added that line myself actually to test if it makes a difference, and it doesn't, memory grows constantly with and without it. Your two links unfortunately don't help either. It wasn't me that downvoted you btw. – Maxi Mus Jan 12 '17 at 20:31
  • Look even [here](http://stackoverflow.com/questions/11204748/memory-leak-in-coreimage-corevideo) it may help – Gor Baghdasaryan Jan 12 '17 at 20:42