You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中传递CVPixelBuffer给CoreImage/UIKit后如何释放?

内存泄漏问题:24位BMP转JPEG时的内存管理异常

我用CVPixelBufferCreateWithBytes(_:_:_:_:_:_:_:_:_:_:)从磁盘读取24位BMP,代码如下:

var data = try! Data(contentsOf: url.appendingPathExtension(for: .bmp))
data.withUnsafeMutableBytes { (unsafeMutableRawBufferPointer: UnsafeMutableRawBufferPointer) in
  var pixelBuffer: CVPixelBuffer?
  CVPixelBufferCreateWithBytes(
    kCFAllocatorDefault,
    imageWidth,
    imageHeight,
    kCVPixelFormatType_24RGB,
    unsafeMutableRawBufferPointer.baseAddress!,
    bytesPerRow,
    nil, nil, nil,
    &pixelBuffer
  )
}

尝试将其转换为JPEG时,所有相关方法都存在内存泄漏,例如:

try! UIImage(ciImage: CIImage(cvPixelBuffer: pixelBuffer!))
    .jpegData(compressionQuality: 0.0)!
    .write(to: someUrl)

以及Core Image的写入方法:

try! CIContext().writeJPEGRepresentation(
    of: CIImage(cvPixelBuffer: pixelBuffer!),
    to: someUrl,
    colorSpace: CGColorSpaceCreateDeviceRGB()
)

使用autoreleasepool包裹代码也无法解决泄漏问题:

autoreleasepool {
  var pixelBuffer: CVPixelBuffer?
  CVPixelBufferCreateWithBytes(
    kCFAllocatorDefault,
    imageWidth,
    imageHeight,
    kCVPixelFormatType_24RGB,
    unsafeMutableRawBufferPointer.baseAddress!,
    bytesPerRow,
    nil, nil, nil,
    &pixelBuffer
  )
  try! UIImage(ciImage: CIImage(cvPixelBuffer: pixelBuffer!))
    .jpegData(compressionQuality: 0.0)!
    .write(to: someUrl)
}

同时,所有*Release方法均不可用,编译器报错:'CFRelease' is unavailable: Core Foundation objects are automatically memory managed。

进一步测试发现,泄漏仅发生在调用JPEG相关方法时:

  • 存在泄漏的代码:
let uiImage = UIImage(ciImage: CIImage(cvPixelBuffer: pixelBuffer!))
    .jpegData(compressionQuality: 0.0)!
  • 无泄漏的代码:
let uiImage = UIImage(ciImage: CIImage(cvPixelBuffer: pixelBuffer!))

Core Image也遵循同样的规律:

  • 无泄漏的代码:
CIContext().createCGImage(CIImage(cvPixelBuffer: pixelBuffer!), from: CGRect(x: 0, y: 0, width: imageWidth, height: imageHeight))
  • 存在泄漏的代码:
CIContext().writeJPEGRepresentation(
    of: CIImage(cvPixelBuffer: pixelBuffer!),
    to: someUrl,
    colorSpace: CGColorSpaceCreateDeviceRGB()
)

我猜测需要通过向CVPixelBufferCreateWithBytes传递CVPixelBufferReleaseBytesCallback来管理内存,但不清楚正确的用法。多数示例给出的回调写法如下:

let releaseCallBack: CVPixelBufferReleaseBytesCallback = { _, pointer in
  if let pointer = pointer {
     free(UnsafeMutableRawPointer(mutating: pointer))
  }
}

但使用该回调会导致autoreleasepool执行时抛出异常,原因是回调试图释放已不存在的内存;如果移除该回调,又会导致对象持续泄漏。手动调用指针的deallocate方法也无法解决问题。

内容的提问来源于stack exchange,提问作者Tae

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 20:50:23