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)
和跟踪图像
问题就在这里:
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)
| 归档时间: |
|
| 查看次数: |
448 次 |
| 最近记录: |