快速读写图像占用大量内存

n s*_*ini 3 macos performance nsimage swift

我正在用 Swift 为 macOS 编写一个叠加图像的应用程序。它工作得很好,但当我做很多次时,记忆就会飞速增长。

我尝试创建一个小项目来读取一张图像,并将其写入 1000 次。图像为15K。该程序需要 2.7 Gb 内存。包含 1000 张图像的实际输出文件夹为 14Mb。

我使用 DispatchQueue.global 让 UI 自由显示操作编号。

如果你有任何想法;)

谢谢,尼古拉斯

这里是代码:

import SwiftUI

struct ContentView: View {
    
    @State private var presentImageImporter = false
    @State private var runningComputation = 1
    @State private var inputImage: NSImage?
    
    var body: some View {
        
        VStack {
            
            Button("Image") {
                presentImageImporter = true
            }.fileImporter(isPresented: $presentImageImporter, allowedContentTypes: [.png, .jpeg]) { result in
                switch result {
                    case .success(let url):
                        if url.startAccessingSecurityScopedResource() {
                               inputImage = NSImage(byReferencing: url)
                            url.stopAccessingSecurityScopedResource()
                        }
                    case .failure(let error):
                        print(error)
                }
            }
            
            Button("Compute 1000 read image") {
                runComputations()
            }
            Divider()
            Text("\(runningComputation)")
            Divider()
        }.frame(minWidth: 200, minHeight: 200)
    }
    
    func runComputations() {
        
                
            let downloadDir = try! FileManager.default.url(
                for: FileManager.SearchPathDirectory.downloadsDirectory,
                in: FileManager.SearchPathDomainMask.userDomainMask,
                appropriateFor: nil,
                create: true)
            
            let subFolder = downloadDir.appendingPathComponent("toto")
        
            try! FileManager.default.createDirectory(at: subFolder, withIntermediateDirectories: true)
            
            DispatchQueue.global(qos: .userInitiated).async {
                for i in 0...1000 {
                    
                    writePNG(inputImage!, url: subFolder.appendingPathComponent("image\(i).png"))
                    
                    runningComputation += 1
                }
            }
            
       
    }
    
}

func writePNG(_ image: NSImage, url: URL) {
    let newRep = NSBitmapImageRep(data: image.tiffRepresentation!)
    newRep!.size = image.size
    let pngData = newRep!.representation(using: .png, properties: [:])
    
    do {
        try pngData!.write(to: url)
    } catch {
        print(error)
    }
}
Run Code Online (Sandbox Code Playgroud)

和跟踪图像

痕迹

Rob*_*ier 5

问题就在这里:

for i in 0...1000 {
    writePNG(inputImage!, url: subFolder.appendingPathComponent("image\(i).png"))                    
    runningComputation += 1
}
Run Code Online (Sandbox Code Playgroud)

这会创建大量临时自动释放对象,而不会耗尽自动释放池。您会注意到,在运行结束时,内存使用量突然下降到 8MiB。那是默认自动释放池耗尽的时候。

您需要将每次迭代包装在自己的autoreleasepool块中,以便更快地丢弃临时对象。

for i in 0...1000 {
    autoreleasepool {
        writePNG(inputImage!, url: subFolder.appendingPathComponent("image\(i).png"))                    
        runningComputation += 1
    }
}
Run Code Online (Sandbox Code Playgroud)