OpenCV MatToUIImage导致内存泄漏 [英] OpenCV MatToUIImage causes memory leak

查看:361
本文介绍了OpenCV MatToUIImage导致内存泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的项目正在使用针对iOS(2.4.9)的openCV.我发现函数 MatToUIImage 会导致内存泄漏,并且仅在iOS 10.X上出现.

My project is working with openCV for iOS(2.4.9). And I found function MatToUIImage which will cause memory leaks, and it only occurs on iOS 10.X.

在我将此功能(2.4.9)更新为最新版本(3.2.0)之后,一切正常.唯一的区别是 CGBitmapInfo .

After I updated this function(2.4.9) to latest(3.2.0) version everything got worked. The only difference is CGBitmapInfo.

那么谁能告诉我为什么?

So can anyone tell me why?

2.4.9

UIImage* MatToUIImage(const cv::Mat& image) {

    NSData *data = [NSData dataWithBytes:image.data
                                  length:image.elemSize()*image.total()];

    CGColorSpaceRef colorSpace;

    if (image.elemSize() == 1) {
        colorSpace = CGColorSpaceCreateDeviceGray();
    } else {
        colorSpace = CGColorSpaceCreateDeviceRGB();
    }

    CGDataProviderRef provider =
            CGDataProviderCreateWithCFData((__bridge CFDataRef)data);

    // Creating CGImage from cv::Mat
    CGImageRef imageRef = CGImageCreate(image.cols,
                                        image.rows,
                                        8,
                                        8 * image.elemSize(),
                                        image.step.p[0],
                                        colorSpace,
                                        kCGImageAlphaNone|
                                        kCGBitmapByteOrderDefault,
                                        provider,
                                        NULL,
                                        false,
                                        kCGRenderingIntentDefault
                                        );


    // Getting UIImage from CGImage
    UIImage *finalImage = [UIImage imageWithCGImage:imageRef];
    CGImageRelease(imageRef);
    CGDataProviderRelease(provider);
    CGColorSpaceRelease(colorSpace);

    return finalImage;
}

3.2.0

UIImage* MatToUIImage(const cv::Mat& image) {

    NSData *data = [NSData dataWithBytes:image.data
                                  length:image.elemSize()*image.total()];

    CGColorSpaceRef colorSpace;

    if (image.elemSize() == 1) {
        colorSpace = CGColorSpaceCreateDeviceGray();
    } else {
        colorSpace = CGColorSpaceCreateDeviceRGB();
    }

    CGDataProviderRef provider =
            CGDataProviderCreateWithCFData((__bridge CFDataRef)data);

    // Preserve alpha transparency, if exists
    bool alpha = image.channels() == 4;
    CGBitmapInfo bitmapInfo = (alpha ? kCGImageAlphaLast : kCGImageAlphaNone) | kCGBitmapByteOrderDefault;

    // Creating CGImage from cv::Mat
    CGImageRef imageRef = CGImageCreate(image.cols,
                                        image.rows,
                                        8,
                                        8 * image.elemSize(),
                                        image.step.p[0],
                                        colorSpace,
                                        bitmapInfo,
                                        provider,
                                        NULL,
                                        false,
                                        kCGRenderingIntentDefault
                                        );


    // Getting UIImage from CGImage
    UIImage *finalImage = [UIImage imageWithCGImage:imageRef];
    CGImageRelease(imageRef);
    CGDataProviderRelease(provider);
    CGColorSpaceRelease(colorSpace);

    return finalImage;
}

推荐答案

重要更新(5.06.2017)最后,手动执行CFRelease并不是一个好主意,因为它可以提高麻烦胜于解决!不过,这给了我一个线索,即泄漏与NSData(非)释放有某种联系.

Important update (5.06.2017) Finally, to perform CFRelease manually turned out to be bad idea as it can raise more troubles than solve! Though, it gave me a clue that leaks are somehow connected with NSData (not-)releasing.

我注意到从后台线程的块中调用它时,它会按预期与ARC自动释放,

I noticed that it's released automatically as expected with ARC when called from block in background thread, like that:

- (void)runInBackgroundWithImageBuffer:(CVImageBufferRef)imageBuffer
                              callback:(void (^)())callback {
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        [self processImageBuffer:imageBuffer];
        if (callback != nil) {
            callback();
        }
    });
}

- (void)previewOpenCVImage:(cv::Mat *)image {
    UIImage *preview = MatToUIImage(*image);

    dispatch_async(dispatch_get_main_queue(), ^{
        // _imagePreview has (UIImageView *) type
        [_imagePreview setImage:preview];
    });
}

我可以确认是否适用于iPhone Simulator .似乎当前的MatToUIImage实现会导致模拟器上的内存泄漏.而且我无法在设备上复制它.

I can confirm that for iPhone Simulator. Seems like current MatToUIImage implementation causes memory leaks on simulator. And I can't reproduce it on device.

由于某些原因,探查器无法检测到它们,但是在多次调用后内存使用量才会爆炸.

我添加了一些调整使其起作用:

  1. 在返回最终图像之前添加第CFRelease((CFTypeRef)data)

当不需要图像时,我们需要执行CFRelease(image.CGImage),可能还需要执行CFRelease((CFTypeRef)image)

When image is not necessary we need to perform CFRelease(image.CGImage) and probably CFRelease((CFTypeRef)image)

希望有帮助.实际上,我不完全了解为什么会发生这种情况,谁持有引用,以及为什么我们需要手动执行发布.

这篇关于OpenCV MatToUIImage导致内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆