#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:)
то, что не кэширует изображение.