另一个iPhone - CGBitmapContextCreateImage泄漏(Another

2019-07-18 06:30发布

就像在这篇文章:

  • iPhone - UIImage的泄漏,建筑ObjectAlloc中

我有一个类似的问题。 从malloc的指针create_bitmap_data_provider永远不会被释放。 我已经验证了相关的图像对象最终被释放,只是没有供应商的分配。 我应该明确地创建一个数据提供并以某种方式管理它的内存? 似乎是一个黑客。

CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(NULL, blah blah blah);
CGColorSpaceRelease(colorSpace);

// ... draw into context

CGImageRef imageRef = CGBitmapContextCreateImage(context);
UIImage * image = [[UIImage alloc] initWithCGImage:imageRef];

CGImageRelease(imageRef);
CGContextRelease(context);

下面fbrereto的回答后,我改变了代码如下:

- (UIImage *)modifiedImage {
    CGSize size = CGSizeMake(width, height);

    UIGraphicsBeginImageContext(size);
    CGContextRef context = UIGraphicsGetCurrentContext();

    // draw into context   

    UIImage * image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return image;  // image retainCount = 1
}    

// caller: 
{
    UIImage * image = [self modifiedImage]; 
    _imageView.image = image; // image retainCount = 2
}

// after caller done, image retainCount = 1, autoreleased object lost its scope

不幸的是,这仍然表现出与水平翻转图像的副作用同样的问题。 这似乎是做同样的事情与CGBitmapContextCreateImage内部。

我已验证对象dealloc被调用。 在该retainCount _imageView.image_imageView均为1之前,我松开_imageView 。 这确实是没有意义的。 其他人似乎有这个问题为好,我是最后一个怀疑SDK,但有可能是一个iPhone SDK的bug这里???

Answer 1:

它看起来像问题是,你是释放指针返回CGImage ,而不是CGImage本身。 我也被以前遇到类似问题与不断增长的分配和最终的应用程序崩溃。 我被分配解决它CGImage ,而不是一个CGImageRef 。 更改后运行Insturments你的代码的分配,你不应该通过malloc看到了永久的内存消耗。 同样,如果你使用类方法imageWithCGImage你会不会担心你的自动释放UIImage以后。

我打字这在PC上,所以如果你把它直接进入的XCode你可能有语法问题,我提前appologize; 然而主要的是声音。

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;


Answer 2:

我有这个问题,它驱使我坚果几天。 经过一番挖掘和利用注意到仪表CG栅格数据泄漏。

这个问题似乎在于内部CoreGraphics中。 我的问题是我是在一个紧凑的循环使用CGBitmapContextCreateImage时,它会在一段时间内保留一些图像(每个800KB),这慢慢泄露出来。

经过与仪器跟踪几天我发现了一个解决方法是使用CGDataProviderCreateWithData方法来代替。 有趣的是输出是一样的CGImageRef但这次将是核芯显卡,并没有泄漏VM没有使用CG栅格数据。 林假设这是内部问题或进行滥用它。

这是救了我的代码:

@autoreleasepool {
    CGImageRef cgImage;
    CreateCGImageFromCVPixelBuffer(pixelBuffer,&cgImage);

    UIImage *image= [UIImage imageWithCGImage:cgImage scale:1.0 orientation:UIImageOrientationUp];

    // DO SOMETHING HERE WITH IMAGE

    CGImageRelease(cgImage);
}

在下面的方法,使用CGDataProviderCreateWithData的关键是。

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 );
    }


Answer 3:

不用手动创建CGContextRef我建议你利用UIGraphicsBeginImageContext在证明这个职位 。 在该组例程的更多细节,可以发现在这里 。 我相信它会有助于解决这个问题,或者至少是给你自己来管理更少的内存。

更新:

鉴于新的代码时, retainCount的的UIImage ,因为它散发出来的作用将是1,并将其分配到的ImageView图像将导致其撞至2.此时取消分配的ImageView将离开retainCount的的UIImage到为1,从而导致泄漏。 这是很重要的,那么,分配后UIImage到的ImageView,以release它。 它可能看起来有点怪,但它会导致retainCount要正确设置为1。



Answer 4:

你不是唯一一个有这个问题。 我有重大问题CGBitmapContextCreateImage()。 当您打开僵尸模式,它甚至警告您的内存被释放两次(当它不是这样)。 有伴的UI *的东西混合CG *的东西时,这绝对是一个问题。 我仍然试图找出如何解决此问题的代码。

附注 :调用UIGraphicsBeginImageContext是不是线程安全的。 小心。



Answer 5:

这真的帮了我! 以下是我用它来解决这个讨厌的泄漏问题:

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

请注意,我不得不存储CFDataRef(对于CFRelease(图像 - > imageRef))在我的〜图像功能。 希望这可以帮助别人...... JR



文章来源: Another iPhone - CGBitmapContextCreateImage Leak