简体   繁体   English

在 UIGraphicsImageRenderer 工作后释放 memory

[英]Release memory after UIGraphicsImageRenderer work

I have many images saved in a Assets.xcassets .我在Assets.xcassets中保存了许多图像。 I'm resizing them, making them smaller.我正在调整它们的大小,使它们变小。 Then later I don't need these images anymore.然后以后我不再需要这些图像了。 Images were not shown, just were prepared.图片没有显示,只是准备好了。 So the class that got images, resized them and kept is now successfully deinited .因此,获取图像、调整大小并保留的class现在已成功取消初始化。
But the memory after UIGraphicsImageRenderer resized the images not released.但是 UIGraphicsImageRenderer 调整大小后的 memory 未发布图像。 Memory usage stayed on the same level. Memory 使用率保持在同一水平。 Even if I didn't use the images at all like in the example code below.即使我根本没有像下面的示例代码那样使用图像。 I think something is wrong.我觉得有些不对劲。 Actually, I resized the images to use less memory but it contrary - resized images use more memory and it do not releasing after the class owner has been deinited.实际上,我调整了图像的大小以使用更少的 memory 但它相反 - 调整大小的图像使用更多的 memory 并且在 class 所有者被定义后它不会释放。

How to release the memory?如何释放 memory?

Apples documentation says: " ...An image renderer keeps a cache of Core Graphics contexts, so reusing the same renderer can be more efficient than creating new renderers ." Apple 的文档说:“ ......图像渲染器保留了 Core Graphics 上下文的缓存,因此重用相同的渲染器可能比创建新的渲染器更有效。” - but I don't need it? - 但我不需要它? How to switch it off.怎么关掉。 With 28 images it seems not big deal, But I have about 100-300 images that should be resized.有 28 张图片似乎没什么大不了的,但我有大约 100-300 张图片需要调整大小。 cropped and other actions with UIGraphicsImageRenderer that at the end of the day uses about 800-900 Mb of the memory that just cache of some render's job that already done.使用 UIGraphicsImageRenderer 进行裁剪和其他操作,最终使用大约 800-900 Mb 的 memory 缓存一些已经完成的渲染工作。

You can take the code below and try.你可以拿下面的代码试试。

class ExampleClass {
    
    func start() {
        Worker().doWork()
    }
}

class Worker {
    
    deinit {
        print("deinit \(Self.self)")
    }
    
    func doWork() {
        
        var urls: [String] = []
        _ = (1...28).map({ urls.append("pathToTheImages/\($0)") })
        // images with resolution 1024.0 x 1366.0 pixels
        
        for url in urls {
            let img = UIImage(named: url)!  // Memory usage: 11.7 MB
            //let cropped = resizedImage(original: img, to: UIScreen.main.bounds.size)
            //With this line above - Memory usage: 17.5 MB even after this class has been deinited
        }
    }
    
    // from 2048 × 3285 pixels >>> to >>> 768.0 x 1024.0 pixels  --- for iPad Pro (9.7-inch)
    func resizedImage(original: UIImage, to size: CGSize) -> UIImage {
        let result = autoreleasepool { () -> UIImage in
            let renderer = UIGraphicsImageRenderer(size: size)
            let result = renderer.image { (context) in
                original.draw(in: CGRect(origin: .zero, size: size))
            }
            return result
        }
        return UIImage(cgImage: result.cgImage!, scale: original.scale, orientation: original.imageOrientation)
    }
}

Asset catalogs are not intended for the use to which you are putting them.资产目录不适用于您放置它们的用途。 The purpose of an image in the asset catalog is to display it, directly.资产目录中图像的目的是直接显示它。 If you have a lot of images that you want to load and resize and save elsewhere without displaying, you need to keep them in your app bundle at the top level, so that you can call init(contentsOfFile:) which does not cache the image.如果您有很多图像要加载和调整大小并保存在其他地方而不显示,则需要将它们保留在顶层的应用程序包中,以便您可以调用不缓存图像的init(contentsOfFile:) .

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM