Swift 3 CGImage内存问题
Swift 3 CGImage Memory issue
我在 Swift3 的代码中有这个函数,实际上我几乎是从 Apple 示例代码中直接翻译过来的。
我的应用程序处理来自相机捕获实时馈送的 sampleBuffers。
此函数正确地从 CMSampleBuffer 创建并 returns 图像。
它工作正常,但内存一直在增长,直到应用程序崩溃。
通过 Instruments,我看到有一些图像数据没有发布。
如果我评论我做 "context.makeImage" 的那一行,内存就会停止。阅读那个 func 文档,它说它从上下文中复制数据。所以我在想有些数据被复制了,一份没有发布。
'problem'是Swift自动处理CoreFoundations内存retains/release,所以我没办法处理
如您所见,我尝试使用自动释放池,但它不起作用。
有什么想法吗?
谢谢
func image(from sampleBuffer:CMSampleBuffer) -> UIImage?{
/* https://developer.apple.com/library/content/qa/qa1702/_index.html */
let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)
guard imageBuffer != nil else{
return nil
}
return autoreleasepool{ () -> UIImage in
CVPixelBufferLockBaseAddress(imageBuffer!, .readOnly);
let baseAddress = CVPixelBufferGetBaseAddress(imageBuffer!)
// Get the number of bytes per row for the pixel buffer
let bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer!);
// Get the pixel buffer width and height
let width = CVPixelBufferGetWidth(imageBuffer!);
let height = CVPixelBufferGetHeight(imageBuffer!);
let colorSpace = CGColorSpaceCreateDeviceRGB();
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue)
.union(.byteOrder32Little)
// Create a bitmap graphics context with the sample buffer data
let context = CGContext(data: baseAddress, width: width, height: height, bitsPerComponent: 8,
bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo.rawValue);
// Create a Quartz image from the pixel data in the bitmap graphics context
let quartzImage = context!.makeImage();
// Unlock the pixel buffer
CVPixelBufferUnlockBaseAddress(imageBuffer!,.readOnly);
let image = UIImage(cgImage: quartzImage!)
return image
}
}
我找到了问题的解决方案。
我不知道 UIKit 不是线程安全的。似乎在与主线程不同的线程中执行该代码不允许系统按应有的方式释放内存。
在主线程上,正确释放和管理内存。
与其他 Core* libraries which are not ARC compliant 一样,您可能需要将 CM 调用包装在自动释放中。
func image(from sampleBuffer:CMSampleBuffer) -> UIImage?{
var ret: UIImage?
autoreleasepool {
/* https://developer.apple.com/library/content/qa/qa1702/_index.html */
let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)
CVPixelBufferLockBaseAddress(imageBuffer!, .readOnly);
let baseAddress = CVPixelBufferGetBaseAddress(imageBuffer!)
// Get the number of bytes per row for the pixel buffer
let bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer!);
// Get the pixel buffer width and height
let width = CVPixelBufferGetWidth(imageBuffer!);
let height = CVPixelBufferGetHeight(imageBuffer!);
let colorSpace = CGColorSpaceCreateDeviceRGB();
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue)
.union(.byteOrder32Little)
// Create a bitmap graphics context with the sample buffer data
let context = CGContext(data: baseAddress, width: width, height: height, bitsPerComponent: 8,
bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo.rawValue);
// Create a Quartz image from the pixel data in the bitmap graphics context
let quartzImage = context!.makeImage();
// Unlock the pixel buffer
CVPixelBufferUnlockBaseAddress(imageBuffer!,.readOnly);
let image = UIImage(cgImage: quartzImage!)
ret = image
}
return ret
}
详情见this answer。
我在 Swift3 的代码中有这个函数,实际上我几乎是从 Apple 示例代码中直接翻译过来的。
我的应用程序处理来自相机捕获实时馈送的 sampleBuffers。
此函数正确地从 CMSampleBuffer 创建并 returns 图像。 它工作正常,但内存一直在增长,直到应用程序崩溃。
通过 Instruments,我看到有一些图像数据没有发布。 如果我评论我做 "context.makeImage" 的那一行,内存就会停止。阅读那个 func 文档,它说它从上下文中复制数据。所以我在想有些数据被复制了,一份没有发布。
'problem'是Swift自动处理CoreFoundations内存retains/release,所以我没办法处理
如您所见,我尝试使用自动释放池,但它不起作用。
有什么想法吗?
谢谢
func image(from sampleBuffer:CMSampleBuffer) -> UIImage?{
/* https://developer.apple.com/library/content/qa/qa1702/_index.html */
let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)
guard imageBuffer != nil else{
return nil
}
return autoreleasepool{ () -> UIImage in
CVPixelBufferLockBaseAddress(imageBuffer!, .readOnly);
let baseAddress = CVPixelBufferGetBaseAddress(imageBuffer!)
// Get the number of bytes per row for the pixel buffer
let bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer!);
// Get the pixel buffer width and height
let width = CVPixelBufferGetWidth(imageBuffer!);
let height = CVPixelBufferGetHeight(imageBuffer!);
let colorSpace = CGColorSpaceCreateDeviceRGB();
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue)
.union(.byteOrder32Little)
// Create a bitmap graphics context with the sample buffer data
let context = CGContext(data: baseAddress, width: width, height: height, bitsPerComponent: 8,
bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo.rawValue);
// Create a Quartz image from the pixel data in the bitmap graphics context
let quartzImage = context!.makeImage();
// Unlock the pixel buffer
CVPixelBufferUnlockBaseAddress(imageBuffer!,.readOnly);
let image = UIImage(cgImage: quartzImage!)
return image
}
}
我找到了问题的解决方案。
我不知道 UIKit 不是线程安全的。似乎在与主线程不同的线程中执行该代码不允许系统按应有的方式释放内存。
在主线程上,正确释放和管理内存。
与其他 Core* libraries which are not ARC compliant 一样,您可能需要将 CM 调用包装在自动释放中。
func image(from sampleBuffer:CMSampleBuffer) -> UIImage?{
var ret: UIImage?
autoreleasepool {
/* https://developer.apple.com/library/content/qa/qa1702/_index.html */
let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)
CVPixelBufferLockBaseAddress(imageBuffer!, .readOnly);
let baseAddress = CVPixelBufferGetBaseAddress(imageBuffer!)
// Get the number of bytes per row for the pixel buffer
let bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer!);
// Get the pixel buffer width and height
let width = CVPixelBufferGetWidth(imageBuffer!);
let height = CVPixelBufferGetHeight(imageBuffer!);
let colorSpace = CGColorSpaceCreateDeviceRGB();
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue)
.union(.byteOrder32Little)
// Create a bitmap graphics context with the sample buffer data
let context = CGContext(data: baseAddress, width: width, height: height, bitsPerComponent: 8,
bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo.rawValue);
// Create a Quartz image from the pixel data in the bitmap graphics context
let quartzImage = context!.makeImage();
// Unlock the pixel buffer
CVPixelBufferUnlockBaseAddress(imageBuffer!,.readOnly);
let image = UIImage(cgImage: quartzImage!)
ret = image
}
return ret
}
详情见this answer。