CIImage память не освобождена

Я пытаюсь сделать последовательность изображений, смешать 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 завершает работу, память соответствующим образом освобождается (однако это уже слишком поздно, так как код может проходить через сотни или тысячи изображений, что заставляет приложение потреблять несколько ТБ данных, прежде чем оно будет выполнено). освобождается). Было бы очень признательно, если бы кто-нибудь увидел в моем коде изъян и то, как сделать его более эффективным с точки зрения памяти.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
956
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы должны использовать функцию 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
    }
}

Вы можете проверить этот Почта, чтобы получить дополнительную информацию.

Спасибо, работает как шарм! Моя память сейчас достигает пика в 1,8 ГБ (для слияния изображений 7x 100 МБ), что значительно меньше, чем раньше. Однако я считаю, что можно еще больше уменьшить занимаемую площадь. Знаете ли вы, есть ли какие-либо побочные эффекты от вложения autoreleasepool? Я считаю, что мог бы иметь еще один autoreleasepool рядом с if let secondImage = ..., но я не уверен, окажет ли это какое-либо негативное влияние.

Jorn 20.12.2018 08:57

Единственное «отрицательное» влияние (я знаю) слишком частого использования autoreleasepool заключается в том, что вы снижаете производительность своего приложения, потому что чаще просите среду выполнения очистить его память. Да, вы можете попробовать добавить второй autoreleasepool вокруг if let secondImage = ....

Yannick Loriot 20.12.2018 11:00

Спасибо за разъяснения :-)

Jorn 22.12.2018 20:56

Другие вопросы по теме