Освободите память после работы UIGraphicsImageRenderer

#ios #swift #memory-management #uiimage #core-graphics

Вопрос:

У меня есть много изображений, сохраненных в файле Assets.xcassets. Я изменяю их размер, делая их меньше. Потом, позже, мне больше не нужны эти изображения. Изображения не показывались, просто были подготовлены. Таким образом, класс, который получил изображения, изменил их размер и сохранил, теперь успешно деинициирован.
Но память после того, как UIGraphicsImageRenderer изменил размер изображений, не была освобождена. Использование памяти осталось на том же уровне. Даже если я вообще не использовал изображения, как в приведенном ниже примере кода. Я думаю, что что-то не так. На самом деле, я изменил размер изображений, чтобы использовать меньше памяти, но это наоборот — измененные изображения используют больше памяти, и они не освобождаются после того, как владелец класса был удален.

Как освободить память?

Документация Apple гласит: «…Средство визуализации изображений сохраняет кэш основных графических контекстов, поэтому повторное использование одного и того же средства визуализации может быть более эффективным, чем создание новых средств визуализации«. — но мне это не нужно! Как его отключить? С 28 изображениями это кажется не таким уж большим делом. Но у меня есть около 100-300 изображений, которые следует изменить, обрезать и выполнить другие действия с помощью UIGraphicsImageRenderer, который в конце дня использует около 800-900 Мб памяти, которая просто кэширует уже выполненную работу рендеринга.

Вы можете взять приведенный ниже код и попробовать.

 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)
    }
}
 

Комментарии:

1. Мне кажется, я видел довольно похожую тему несколько дней назад.

2. Вы жалуетесь, что графические контексты средства визуализации изображений не освобождаются или что изображения не освобождаются? О какой памяти идет речь? Используйте инструменты, чтобы выяснить это.

3. @мэтт, я спрашиваю о графическом контексте визуализации, а не об изображении. Все объекты UIImage были деинициированы.

4. Возможно, они были деинициированы, но они также кэшированы. Мне кажется, что вы просто догадываетесь. Не. Используйте Инструменты.

5. @мэтт, хорошо. Я вижу в Инструментах (Распределения) — 28 изображений распределены. Я знаю, что они кэшировали. В этом проблема и мой первоначальный вопрос. Как освободить память и избавиться от кэшированных изображений, которые занимают больше памяти, чем их более крупные оригиналы?

Ответ №1:

Каталоги активов не предназначены для использования, для которого вы их размещаете. Цель изображения в каталоге активов заключается в его непосредственном отображении. Если у вас есть много изображений, которые вы хотите загрузить, изменить размер и сохранить в другом месте без отображения, вам нужно сохранить их в пакете приложений на верхнем уровне, чтобы вы могли вызвать init(contentsOfFile:) то, что не кэширует изображение.