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
实现导致模拟器上的内存泄漏。 我不能在设备上重现它。
由于某些原因,他们不被探测器检测到,但多次调用后,内存使用情况正好爆发。
我已经添加了一些调整,使其工作:
-
在返回最终图像之前添加CFRelease((CFTypeRef)data)
-
当图像不是必要的,我们需要执行CFRelease(image.CGImage)
,可能CFRelease((CFTypeRef)image)
希望有所帮助。 其实我不完全理解为什么会发生这种情况,谁持有引用,为什么我们需要手动执行发布。