Swift - NSImage,内存泄漏?
Swift - NSImage, memory leak?
给出以下任务:
- 扫描一个文件夹,其中包含有图像的子文件夹,并确保 none 个图像已损坏
- 使用 MacOS 和 Swift
- 打开每个图像并检查它是否损坏
我写了这个小小的命令行程序:
import ArgumentParser
import AppKit
import Foundation
struct CheckImages: ParsableCommand {
@Option(help: "The images root directory")
var path: String
func run() throws {
let directories = try FileManager.default.contentsOfDirectory(atPath: path)
for directory in directories {
if directory == ".DS_Store" {
continue
}
let prefix = self.path + "\(directory)/PREFIX_\(directory)"
let imageName = prefix + ".jpg"
let image = NSImage(contentsOfFile: imageName)
if image == nil {
print("PROBLEM \(imageName)")
}
}
}
}
CheckImages.main()
每张图片大小约为 20MB。我总共有 ~150.000 张图片要检查。
不幸的是 XCode 以 Program ended with exit code: 9
终止了程序。深入挖掘(使用 Instruments)发现这个小小的帮助应用程序占用了我 NSImage.init()
中的所有内存。由于 NSImage
是一个成熟的对象,我怀疑它有什么问题。因此,我的问题是,任何人都可以向我解释这种行为吗?
我的环境:
- XCode 版本 11.4.1 (11E503a)
- Apple Swift 版本 5.2.2 (swiftlang-1103.0.32.6 clang-1103.0.32.51)
回答我自己的问题,我需要一个自动释放池。因为我从未在 Objective-C 中编程,所以我不知道自动释放池之类的东西。由于 NSImage
是 'just' ObjC-NSImage 对象的包装器,它需要一个自动释放池来管理释放。都2020年了,还得这么管?
在这个post中我找到了上述问题的答案:Is it necessary to use autoreleasepool in a Swift program?
另一个不错的 post 可以在这里找到:https://swiftrocks.com/autoreleasepool-in-2019-swift.html
因此,上面的代码必须如下所示:
import ArgumentParser
import AppKit
import Foundation
struct CheckImages: ParsableCommand {
@Option(help: "The images root directory")
var path: String
func run() throws {
let directories = try FileManager.default.contentsOfDirectory(atPath: path)
for directory in directories {
if directory == ".DS_Store" {
continue
}
autoreleasepool {
let prefix = self.path + "\(directory)/PREFIX_\(directory)"
let imageName = prefix + ".jpg"
let image = NSImage(contentsOfFile: imageName)
if image == nil {
print("PROBLEM \(imageName)")
}
}
}
}
}
CheckImages.main()
给出以下任务:
- 扫描一个文件夹,其中包含有图像的子文件夹,并确保 none 个图像已损坏
- 使用 MacOS 和 Swift
- 打开每个图像并检查它是否损坏
我写了这个小小的命令行程序:
import ArgumentParser
import AppKit
import Foundation
struct CheckImages: ParsableCommand {
@Option(help: "The images root directory")
var path: String
func run() throws {
let directories = try FileManager.default.contentsOfDirectory(atPath: path)
for directory in directories {
if directory == ".DS_Store" {
continue
}
let prefix = self.path + "\(directory)/PREFIX_\(directory)"
let imageName = prefix + ".jpg"
let image = NSImage(contentsOfFile: imageName)
if image == nil {
print("PROBLEM \(imageName)")
}
}
}
}
CheckImages.main()
每张图片大小约为 20MB。我总共有 ~150.000 张图片要检查。
不幸的是 XCode 以 Program ended with exit code: 9
终止了程序。深入挖掘(使用 Instruments)发现这个小小的帮助应用程序占用了我 NSImage.init()
中的所有内存。由于 NSImage
是一个成熟的对象,我怀疑它有什么问题。因此,我的问题是,任何人都可以向我解释这种行为吗?
我的环境:
- XCode 版本 11.4.1 (11E503a)
- Apple Swift 版本 5.2.2 (swiftlang-1103.0.32.6 clang-1103.0.32.51)
回答我自己的问题,我需要一个自动释放池。因为我从未在 Objective-C 中编程,所以我不知道自动释放池之类的东西。由于 NSImage
是 'just' ObjC-NSImage 对象的包装器,它需要一个自动释放池来管理释放。都2020年了,还得这么管?
在这个post中我找到了上述问题的答案:Is it necessary to use autoreleasepool in a Swift program?
另一个不错的 post 可以在这里找到:https://swiftrocks.com/autoreleasepool-in-2019-swift.html
因此,上面的代码必须如下所示:
import ArgumentParser
import AppKit
import Foundation
struct CheckImages: ParsableCommand {
@Option(help: "The images root directory")
var path: String
func run() throws {
let directories = try FileManager.default.contentsOfDirectory(atPath: path)
for directory in directories {
if directory == ".DS_Store" {
continue
}
autoreleasepool {
let prefix = self.path + "\(directory)/PREFIX_\(directory)"
let imageName = prefix + ".jpg"
let image = NSImage(contentsOfFile: imageName)
if image == nil {
print("PROBLEM \(imageName)")
}
}
}
}
}
CheckImages.main()