【问题标题】:CIImage memory not releasedCIImage内存未释放
【发布时间】:2019-05-19 05:55:17
【问题描述】:

我正在尝试拍摄一系列图像,同时混合 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
    }
}

还有 CIImage 的 blend 函数的代码

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
    }
}

正如代码中的 cmets 所详述,我希望在 firstImage 和 secondImage 中分配的内存在它们创建的范围结束时被释放。因为它们都是在 while 循环中创建的,所以我希望它们然而,在该循环结束时被释放,这似乎没有发生。但是这里没有内存泄漏,因为当blendImages函数完成时,内存被适当地释放了(然而,这为时已晚,因为代码可能会运行成百上千张图像,使得应用程序之前消耗了几TB的数据它被释放)。 如果有人能看到我的代码中的缺陷以及如何提高内存效率,将不胜感激。

【问题讨论】:

    标签: swift macos cifilter swift4.2 ciimage


    【解决方案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
        }
    }
    

    您可以查看此post 以了解更多信息。

    【讨论】:

    • 谢谢你,就像一个魅力!我的内存现在达到了 1.8 GB 的峰值(对于 7x 100 MB 的图像合并),这比以前要低得多。但是,我相信应该可以进一步减少占用空间。不知道嵌套autoreleasepools有什么不良影响吗?我相信我可以在if let secondImage = ... 周围再有一个autoreleasepool,但我不确定这是否有任何负面影响。
    • 经常使用autoreleasepool 唯一的“负面”影响(我知道)是您降低了应用程序的性能,因为您更频繁地要求运行时清理其内存。是的,您可以尝试在 if let secondImage = ... 周围添加第二个 autoreleasepool
    • 感谢您的澄清 :-)
    猜你喜欢
    • 2019-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-21
    • 2015-06-21
    • 2012-05-22
    • 1970-01-01
    相关资源
    最近更新 更多