Swift - NSImage, утечка памяти? - PullRequest
0 голосов
/ 20 апреля 2020

Дается следующая задача:

  • Сканирование папки, которая содержит подпапки с изображениями внутри, и убедитесь, что ни одно из изображений не повреждено
  • Используйте 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()

Каждое изображение имеет размер около 20 МБ. В общей сложности у меня есть ~ 150 000 изображений для проверки.

К сожалению, XCode завершает программу с Program ended with exit code: 9. Если копнуть глубже (с помощью инструментов), то выясняется, что это небольшое приложение справки потребляет всю мою память в NSImage.init(). Поскольку NSImage является зрелым объектом, я сомневаюсь, что есть какие-либо проблемы с ним. Таким образом, мой вопрос: кто-нибудь может объяснить мне это поведение?

Мое окружение:

  • XCode версии 11.4.1 (11E503a)
  • Apple Swift версии 5.2 .2 (swiftlang-1103.0.32.6 clang-1103.0.32.51)

1 Ответ

1 голос
/ 22 апреля 2020

Отвечая на мой собственный вопрос, мне нужен пул авто-релизов здесь. Поскольку я никогда не программировал в Objective- C, я не знал о таких вещах, как пулы авто-релиза. Поскольку NSImage является «просто» оберткой вокруг объекта Obj C -NSImage, ему необходим пул авто-релиза для управления освобождением. Мы находимся в 2020 году, и мы должны управлять такими вещами таким образом?

В этом посте я нашел ответ на вышеуказанную проблему: Нужно ли использовать автозапуск в программе Swift?

Еще один хороший пост можно найти здесь: 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()
...