Swift 5 MacOS Image Resize 内存问题

Posted

技术标签:

【中文标题】Swift 5 MacOS Image Resize 内存问题【英文标题】:Swift5 MacOS ImageResize memory issue 【发布时间】:2021-04-12 18:49:15 【问题描述】:

我是使用 Swift 开发 Mac OS 应用程序的新手。但我尝试制作简单的 ImageResizer 应用程序。我必须调整 50k 图像的大小。 10小时后,内存增加到近120GB。我认为 Swift 也有垃圾收集器。为什么会增加内存?我会告诉你我的代码。

for i in 0..<paths.count 
    let path = paths[i]

    if let image = NSImage(contentsOf: path) 
        ...

        if self.resize(image: image, size: size, to: URL(fileURLWithPath: resizedImagePath)) 
            print("Image saved to \(resizedImagePath)")
            continue
        
    


func resize(image: NSImage, size: Int, to url: URL) -> Bool 
    if !image.isValid 
        print("invalid image")
        return false
    

    guard let pixelsWide = image.representations.first?.pixelsWide else 
        return false
    

    let factor: CGFloat = CGFloat(pixelsWide) / image.size.width

    var width: CGFloat = CGFloat(size)
    var height: CGFloat = CGFloat(size)
    if image.size.width > image.size.height 
        height = width * image.size.height / image.size.width
     else 
        width = height * image.size.width / image.size.height
    

    let rep = NSBitmapImageRep(bitmapDataPlanes: nil,
                               pixelsWide: Int(width),
                               pixelsHigh: Int(height),
                               bitsPerSample: 8,
                               samplesPerPixel: 4,
                               hasAlpha: true,
                               isPlanar: false,
                               colorSpaceName: .deviceRGB,
                               bytesPerRow: Int(width * 4),
                               bitsPerPixel: 32)
    rep?.size = NSSize(width: width / factor, height: height / factor)

    let ctx = NSGraphicsContext(bitmapImageRep: rep!)
    NSGraphicsContext.saveGraphicsState()
    NSGraphicsContext.current = ctx
    image.draw(in: NSMakeRect(0, 0, width / factor, height / factor))
    ctx?.flushGraphics()
    NSGraphicsContext.restoreGraphicsState()

    // Get NSData, and save it
    let data = rep?.representation(using: .png, properties: [:]) // properties as! [String : Any]) //
    do 
        try data?.write(to: url)
        return true
    
    catch 
        return false
    

【问题讨论】:

【参考方案1】:

Swift 使用 ARC(自动引用计数),这意味着当对该对象的强引用数量达到零时,对象将被释放。我没有立即在提供的代码中看到问题出在哪里,但我怀疑您的代码中的其他地方一定有某个位置您持有对图像的引用。

【讨论】:

它没有其他可以增加内存的代码。其他代码只是获取目标路径。如果我删除提供的代码,那么它需要不到 1 秒并且不会增加内存。【参考方案2】:

您可以将循环中的整个代码放在autoreleasepool 中:

如果您编写一个创建许多临时对象的循环。您可以使用 循环内的自动释放池块以处理这些对象 在下一次迭代之前。在循环中使用自动释放池块 有助于减少应用程序的最大内存占用。

for i in paths.indices 
    autoreleasepool 
        // all your image resizing code goes here
    

【讨论】:

以上是关于Swift 5 MacOS Image Resize 内存问题的主要内容,如果未能解决你的问题,请参考以下文章

如何从 macOS Swift 上的文档目录加载图像?

iTunesLibrary Swift 5.3 macOS

在 macOS 的 swift 5 中声明 ExtAudioFileRef 的正确方法

Xcode Swift 5 MacOs 应用程序存档时为空窗口,但在从 Xcode 运行时有效

Swift更加开放,不再限于macOS与Ubuntu

Swift Publisher 5.5.3安装教程