Я пытаюсь сделать последовательность изображений, смешать X изображений за раз и создать новое изображение. Вот код, который я должен выполнить:
static func blendImages(blendFrames: Int, blendMode: CIImage.BlendMode, imagePaths: [URL], completion: @escaping (_ progress: Double) -> Void) {
var currentIndex = 0
while currentIndex + blendFrames < imagePaths.count {
let currentSubset = Array(imagePaths[currentIndex..<(currentIndex + blendFrames)])
var currentSubsetIndex = 0
var firstImage: CIImage?
while currentSubset.count > currentSubsetIndex + 1 {
if firstImage == nil { firstImage = CIImage(contentsOf: currentSubset[currentSubsetIndex]) } //First image allocated in memory
if let secondImage = CIImage(contentsOf: currentSubset[currentSubsetIndex + 1]) {//Second image allocated in memory
firstImage = firstImage?.blend(with: secondImage, blendMode: blendMode)
} //Would expect secondImage to be freed from memory at this point, but it does not happen
currentSubsetIndex += 1
}
if let finalImage = firstImage {
let bitMapRep = NSBitmapImageRep(ciImage: finalImage)
let data = bitMapRep.representation(using: .jpeg, properties: [:])
do {
try data?.write(to: URL(fileURLWithPath: "Final-" + String(format: "%03d", currentIndex) + ".jpg"))
} catch let error as NSError {
print("Failed to write to disk: \(error)")
}
}
firstImage = nil //Would expect firstImage to be freed from memory at this point (or at beginning of next cycle in while-loop), but it does not happen
currentIndex += 1
}
}
И код функции blend CIImage
extension CIImage {
enum BlendMode: String {
case Lighten = "CILightenBlendMode"
case Darken = "CIDarkenBlendMode"
}
func blend(with image: CIImage, blendMode: BlendMode) -> CIImage? {
let filter = CIFilter(name: blendMode.rawValue)!
filter.setDefaults()
filter.setValue(self, forKey: "inputImage")
filter.setValue(image, forKey: "inputBackgroundImage")
return filter.outputImage
}
}
Как подробно описано в комментариях в коде, я ожидал, что память, выделенная в firstImage и secondImage, будет освобождена в конце области, в которой они созданы. Поскольку они оба созданы в цикле while, я ожидал, что они будут освобождены однако в конце этого цикла этого не происходит. Но здесь нет утечки памяти, потому что, когда функция blendImages завершает работу, память соответствующим образом освобождается (однако это уже слишком поздно, так как код может проходить через сотни или тысячи изображений, что заставляет приложение потреблять несколько ТБ данных, прежде чем оно будет выполнено). освобождается).
Было бы очень признательно, если бы кто-нибудь увидел в моем коде изъян и то, как сделать его более эффективным с точки зрения памяти.





Вы должны использовать функцию autoreleasepool, чтобы принудительно освободить объекты внутри ее области видимости. Эта функция поможет вам более точно управлять объемом памяти.
static func blendImages(blendFrames: Int, blendMode: CIImage.BlendMode, imagePaths: [URL], completion: @escaping (_ progress: Double) -> Void) {
var currentIndex = 0
while currentIndex + blendFrames < imagePaths.count {
autorelease {
// your code
}
currentIndex += 1
}
}
Вы можете проверить этот Почта, чтобы получить дополнительную информацию.
Единственное «отрицательное» влияние (я знаю) слишком частого использования autoreleasepool заключается в том, что вы снижаете производительность своего приложения, потому что чаще просите среду выполнения очистить его память. Да, вы можете попробовать добавить второй autoreleasepool вокруг if let secondImage = ....
Спасибо за разъяснения :-)
Спасибо, работает как шарм! Моя память сейчас достигает пика в 1,8 ГБ (для слияния изображений 7x 100 МБ), что значительно меньше, чем раньше. Однако я считаю, что можно еще больше уменьшить занимаемую площадь. Знаете ли вы, есть ли какие-либо побочные эффекты от вложения
autoreleasepool? Я считаю, что мог бы иметь еще одинautoreleasepoolрядом сif let secondImage = ..., но я не уверен, окажет ли это какое-либо негативное влияние.