Another iPhone - CGBitmapContextCreateImage Leak

后端 未结 5 1413
心在旅途
心在旅途 2020-12-10 08:40

Like in this post:

  • iPhone - UIImage Leak, ObjectAlloc Building

I\'m having a similar problem. The pointer from the malloc in create_bitmap

相关标签:
5条回答
  • 2020-12-10 09:11

    It looks like the problem is that you are releasing a pointer to the returned CGImage, rather than the CGImage itself. I too was having similar issues before with continual growing allocations and an eventual app crash. I addressed it by allocating a CGImage rather than a CGImageRef. After the changes run your code in Insturments with allocations, and you should not see anymore perpetual memory consumption from malloc. As well if you use the class method imageWithCGImage you will not have to worry about autoreleasing your UIImage later on.

    I typed this on a PC so if you drop it right into XCode you may have syntax issue, I appologize in advance; however the principal is sound.

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
    CGContextRef context = CGBitmapContextCreate(NULL, blah blah blah); 
    CGColorSpaceRelease(colorSpace);
    
    // ... draw into context  
    
    CGImage cgImage = CGBitmapContextCreateImage(context); 
    UIImage * image = [UIImage imageWithCGImage:cgImage];  
    CGImageRelease(cgImage); 
    CGContextRelease(context);
    return image;
    
    0 讨论(0)
  • 2020-12-10 09:11

    This really helped me! Here's how I used it to fix that nasty leak problem:

        CGImage *cgImage = CGBitmapContextCreateImage(context);
        CFDataRef dataRef = CGDataProviderCopyData(CGImageGetDataProvider(cgImage));
        CGImageRelease(cgImage);
        image->imageRef = dataRef;
        image->image = CFDataGetBytePtr(dataRef);
    

    Notice, I had to store the CFDataRef (for a CFRelease(image->imageRef)) in my ~Image function. Hopefully this also helps others...JR

    0 讨论(0)
  • 2020-12-10 09:20

    I had this problem and it drove me nuts for a few days. After much digging and noticing a leak in CG Raster Data using Instruments.

    The problem seems to lie inside CoreGraphics. My problem was when i was using CGBitmapContextCreateImage in a tight loop it would over a period of time retain some images (800kb each) and this slowly leaked out.

    After a few days of tracing with Instruments I found a workaround was to use CGDataProviderCreateWithData method instead. The interesting thing was the output was the same CGImageRef but this time there would be no CG Raster Data used in VM by Core graphics and no leak. Im assuming this is an internal problem or were misusing it.

    Here is the code that saved me:

    @autoreleasepool {
        CGImageRef cgImage;
        CreateCGImageFromCVPixelBuffer(pixelBuffer,&cgImage);
    
        UIImage *image= [UIImage imageWithCGImage:cgImage scale:1.0 orientation:UIImageOrientationUp];
    
        // DO SOMETHING HERE WITH IMAGE
    
        CGImageRelease(cgImage);
    }
    

    The key was using CGDataProviderCreateWithData in the method below.

    static OSStatus CreateCGImageFromCVPixelBuffer(CVPixelBufferRef pixelBuffer, CGImageRef *imageOut)
        {
            OSStatus err = noErr;
            OSType sourcePixelFormat;
            size_t width, height, sourceRowBytes;
            void *sourceBaseAddr = NULL;
            CGBitmapInfo bitmapInfo;
            CGColorSpaceRef colorspace = NULL;
            CGDataProviderRef provider = NULL;
            CGImageRef image = NULL;
    
            sourcePixelFormat = CVPixelBufferGetPixelFormatType( pixelBuffer );
            if ( kCVPixelFormatType_32ARGB == sourcePixelFormat )
                bitmapInfo = kCGBitmapByteOrder32Big | kCGImageAlphaNoneSkipFirst;
            else if ( kCVPixelFormatType_32BGRA == sourcePixelFormat )
                bitmapInfo = kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst;
            else
                return -95014; // only uncompressed pixel formats
    
            sourceRowBytes = CVPixelBufferGetBytesPerRow( pixelBuffer );
            width = CVPixelBufferGetWidth( pixelBuffer );
            height = CVPixelBufferGetHeight( pixelBuffer );
    
            CVPixelBufferLockBaseAddress( pixelBuffer, 0 );
            sourceBaseAddr = CVPixelBufferGetBaseAddress( pixelBuffer );
    
            colorspace = CGColorSpaceCreateDeviceRGB();
    
            CVPixelBufferRetain( pixelBuffer );
            provider = CGDataProviderCreateWithData( (void *)pixelBuffer, sourceBaseAddr, sourceRowBytes * height, ReleaseCVPixelBuffer);
            image = CGImageCreate(width, height, 8, 32, sourceRowBytes, colorspace, bitmapInfo, provider, NULL, true, kCGRenderingIntentDefault);
    
            if ( err && image ) {
                CGImageRelease( image );
                image = NULL;
            }
            if ( provider ) CGDataProviderRelease( provider );
            if ( colorspace ) CGColorSpaceRelease( colorspace );
            *imageOut = image;
            return err;
        }
    
        static void ReleaseCVPixelBuffer(void *pixel, const void *data, size_t size)
        {
            CVPixelBufferRef pixelBuffer = (CVPixelBufferRef)pixel;
            CVPixelBufferUnlockBaseAddress( pixelBuffer, 0 );
            CVPixelBufferRelease( pixelBuffer );
        }
    
    0 讨论(0)
  • 2020-12-10 09:21

    Instead of manually creating your CGContextRef I'd suggest you leverage UIGraphicsBeginImageContext as demonstrated in this post. More details on that set of routines can be found here. I trust it'll help to resolve this issue, or at the very least give you less memory you have to manage yourself.

    UPDATE:

    Given the new code, the retainCount of the UIImage as it comes out of the function will be 1, and assigning it to the imageView's image will cause it to bump to 2. At that point deallocating the imageView will leave the retainCount of the UIImage to be 1, resulting in a leak. It is important, then, after assigning the UIImage to the imageView, to release it. It may look a bit strange, but it will cause the retainCount to be properly set to 1.

    0 讨论(0)
  • 2020-12-10 09:25

    You're not the only one with this problem. I've had major problems with CGBitmapContextCreateImage(). When you turn on Zombie mode, it even warns you that memory is released twice (when it's not the case). There's definitely a problem when mixing CG* stuff with UI* stuff. I'm still trying to figure out how to code around this issue.

    Side note: calling UIGraphicsBeginImageContext is not thread-safe. Be careful.

    0 讨论(0)
提交回复
热议问题