CGImageRef Memory leak

2019-01-19 05:38发布

问题:

I'm having a memory leak when using this custom method which returns a CGImageRef. I can't release "cgImage" properly because I have to return it. What chould I do ?

- (CGImageRef)rectRoundedImageRef:(CGRect)rect radius:(int)radius
{
    CGSize contextSize = CGSizeMake(rect.size.width, rect.size.height);     
    CGFloat imageScale = (CGFloat)1.0;
    CGFloat width = contextSize.width;
    CGFloat height = contextSize.height;        
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(NULL, width * imageScale, height * imageScale, 8, 0, colorSpace, kCGImageAlphaPremultipliedLast);
    // Draw ...
    // Get your image
    CGImageRef cgImage = CGBitmapContextCreateImage(context);       
    CGColorSpaceRelease(colorSpace);
    CGContextRelease(context);
    //CGImageRelease(cgImage); //If I release cgImage the app crashes.
    return cgImage;     
}

回答1:

cgImage is owned by your method, you need to return it and give responsibility to the caller to release it through CFRelease.

You can also return the CGImage wrapped inside a UIImage instance, like this:

UIImage *image = [UIImage imageWithCGImage:cgImage];
CFRelease(cgImage); //cgImage is retained by the UIImage above
return image;


回答2:

This is a general problem with Core Foundation objects because there is no autorelease pool in CF. As I see it, you have two options to solve the problem:

  1. Rename the method to something like -newRectRoundedImageRef:radius: to tell the caller that he takes ownership of the returned object and responsible for releasing it.
  2. Wrap the CGImageRef in an autoreleased UIImage object and return that ([UIImage imageWithCGImage:]). That's probably what I would do.


回答3:

You can autorelease a Core Foundation-compatible object. it just looks a bit wonky. :)

The GC-safe way is like so:

CGImageRef image = ...;
if (image) {
    image = (CGImageRef)[[(id)image retain] autorelease];
    CGImageRelease(image);
}

The shortcut, which is safe on iOS but no longer safe on the Mac, is this:

CGImageRef image = ...;
if (image) {
    image = (CGImageRef)[(id)image autorelease];
}

Either one will place the image in an autorelease pool and prevent a leak.



回答4:

As suggested, we used:

CGImageRelease(imageRef);

but we still got an memory leak. our solution was to wrap code with an

@autoreleasepool {}

block and that solve our problem.