OpenCV MatToUIImage导致内存泄漏

我的项目正在与iOS的openCV(2.4.9)。 我发现MatToUIImage函数会导致内存泄漏,只发生在iOS 10.X上。

在我更新这个函数(2.4.9)到最新的(3.2.0)版本之后,所有的东西都得到了工作。 唯一的区别是CGBitmapInfo

那么有谁能告诉我为什么?

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 (不)释放。

我注意到,如果在后台线程中从块中调用ARC,它会像预期的那样自动发布:

 - (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模拟器 。 似乎目前的MatToUIImage实现导致模拟器上的内存泄漏。 我不能在设备上重现它。

由于某些原因,他们不被探测器检测到,但多次调用后,内存使用情况正好爆发。

我已经添加了一些调整,使其工作:

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

  2. 当图像不是必要的,我们需要执行CFRelease(image.CGImage) ,可能CFRelease((CFTypeRef)image)

希望有所帮助。 其实我不完全理解为什么会发生这种情况,谁持有引用,为什么我们需要手动执行发布。