如何手动释放CMSampleBuffer
How to manually release CMSampleBuffer
此代码导致内存泄漏和应用程序崩溃:
var outputSamples = [Float]()
assetReader.startReading()
while assetReader.status == .reading {
let trackOutput = assetReader.outputs.first!
if let sampleBuffer = trackOutput.copyNextSampleBuffer(),
let blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer) {
let blockBufferLength = CMBlockBufferGetDataLength(blockBuffer)
let sampleLength = CMSampleBufferGetNumSamples(sampleBuffer) * channelCount(from: assetReader)
var data = Data(capacity: blockBufferLength)
data.withUnsafeMutableBytes { (blockSamples: UnsafeMutablePointer<Int16>) in
CMBlockBufferCopyDataBytes(blockBuffer, atOffset: 0, dataLength: blockBufferLength, destination: blockSamples)
CMSampleBufferInvalidate(sampleBuffer)
let processedSamples = process(blockSamples,
ofLength: sampleLength,
from: assetReader,
downsampledTo: targetSampleCount)
outputSamples += processedSamples
}
}
}
var paddedSamples = [Float](repeating: silenceDbThreshold, count: targetSampleCount)
paddedSamples.replaceSubrange(0..<min(targetSampleCount, outputSamples.count), with: outputSamples)
这是由于 copyNextSampleBuffer() and The Create Rule。
反过来,我们不能在Swift中使用CFRelease()。 link 到 Objective-C only 规则的原因超出了我的理解。
有没有办法在Swift中手动释放CMSampleBuffer?
这不是真正的解决方案,因为手动释放内存似乎是不可能的,并且将 while 循环与 assetReader 结合使用会导致在读取不安全的可变字节时不会释放内存。
问题已通过解决方法解决:在将音频文件暴露给 while 循环之前将其转换为 CAF 格式。
缺点:需要一秒钟的时间,音频文件越长 - 花费的时间越多。
好处:它只使用了极少量的内存,这才是问题的首要所在。
灵感来自:https://whosebug.com/users/2907715/carpsen90 answer in
我最近使用自动释放池解决了类似的问题
尝试将 sampleBuffer
使用的区域包裹在自动释放池中。像这样:
var outputSamples = [Float]()
assetReader.startReading()
while assetReader.status == .reading {
let trackOutput = assetReader.outputs.first!
autoreleasepool {
if let sampleBuffer = trackOutput.copyNextSampleBuffer(),
let blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer) {
let blockBufferLength = CMBlockBufferGetDataLength(blockBuffer)
let sampleLength = CMSampleBufferGetNumSamples(sampleBuffer) * channelCount(from: assetReader)
var data = Data(capacity: blockBufferLength)
data.withUnsafeMutableBytes { (blockSamples: UnsafeMutablePointer<Int16>) in
CMBlockBufferCopyDataBytes(blockBuffer, atOffset: 0, dataLength: blockBufferLength, destination: blockSamples)
CMSampleBufferInvalidate(sampleBuffer)
let processedSamples = process(blockSamples,
ofLength: sampleLength,
from: assetReader,
downsampledTo: targetSampleCount)
outputSamples += processedSamples
}
}
}
}
var paddedSamples = [Float](repeating: silenceDbThreshold, count: targetSampleCount)
paddedSamples.replaceSubrange(0..<min(targetSampleCount, outputSamples.count), with: outputSamples)
如果我没理解错的话,一旦移出autoreleasepool
的范围,sampleBuffer就会被释放
此代码导致内存泄漏和应用程序崩溃:
var outputSamples = [Float]()
assetReader.startReading()
while assetReader.status == .reading {
let trackOutput = assetReader.outputs.first!
if let sampleBuffer = trackOutput.copyNextSampleBuffer(),
let blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer) {
let blockBufferLength = CMBlockBufferGetDataLength(blockBuffer)
let sampleLength = CMSampleBufferGetNumSamples(sampleBuffer) * channelCount(from: assetReader)
var data = Data(capacity: blockBufferLength)
data.withUnsafeMutableBytes { (blockSamples: UnsafeMutablePointer<Int16>) in
CMBlockBufferCopyDataBytes(blockBuffer, atOffset: 0, dataLength: blockBufferLength, destination: blockSamples)
CMSampleBufferInvalidate(sampleBuffer)
let processedSamples = process(blockSamples,
ofLength: sampleLength,
from: assetReader,
downsampledTo: targetSampleCount)
outputSamples += processedSamples
}
}
}
var paddedSamples = [Float](repeating: silenceDbThreshold, count: targetSampleCount)
paddedSamples.replaceSubrange(0..<min(targetSampleCount, outputSamples.count), with: outputSamples)
这是由于 copyNextSampleBuffer() and The Create Rule。
反过来,我们不能在Swift中使用CFRelease()。 link 到 Objective-C only 规则的原因超出了我的理解。
有没有办法在Swift中手动释放CMSampleBuffer?
这不是真正的解决方案,因为手动释放内存似乎是不可能的,并且将 while 循环与 assetReader 结合使用会导致在读取不安全的可变字节时不会释放内存。
问题已通过解决方法解决:在将音频文件暴露给 while 循环之前将其转换为 CAF 格式。
缺点:需要一秒钟的时间,音频文件越长 - 花费的时间越多。
好处:它只使用了极少量的内存,这才是问题的首要所在。
灵感来自:https://whosebug.com/users/2907715/carpsen90 answer in
我最近使用自动释放池解决了类似的问题
尝试将 sampleBuffer
使用的区域包裹在自动释放池中。像这样:
var outputSamples = [Float]()
assetReader.startReading()
while assetReader.status == .reading {
let trackOutput = assetReader.outputs.first!
autoreleasepool {
if let sampleBuffer = trackOutput.copyNextSampleBuffer(),
let blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer) {
let blockBufferLength = CMBlockBufferGetDataLength(blockBuffer)
let sampleLength = CMSampleBufferGetNumSamples(sampleBuffer) * channelCount(from: assetReader)
var data = Data(capacity: blockBufferLength)
data.withUnsafeMutableBytes { (blockSamples: UnsafeMutablePointer<Int16>) in
CMBlockBufferCopyDataBytes(blockBuffer, atOffset: 0, dataLength: blockBufferLength, destination: blockSamples)
CMSampleBufferInvalidate(sampleBuffer)
let processedSamples = process(blockSamples,
ofLength: sampleLength,
from: assetReader,
downsampledTo: targetSampleCount)
outputSamples += processedSamples
}
}
}
}
var paddedSamples = [Float](repeating: silenceDbThreshold, count: targetSampleCount)
paddedSamples.replaceSubrange(0..<min(targetSampleCount, outputSamples.count), with: outputSamples)
如果我没理解错的话,一旦移出autoreleasepool
的范围,sampleBuffer就会被释放