循环清除内存
Clear memory on cycle
我有一组图像,需要使用不同的混合选项合并这些图像。我发现,在此过程中,内存不会在循环的每个步骤中释放。即使没有对创建的图像的引用。在此过程中,我的应用程序崩溃了,因为我有很多图像要合并。有什么解决方法或技巧可以在不增加内存的情况下做到这一点吗?
可以使用以下代码重现:
import UIKit
import CoreImage
class ViewController: UIViewController {
var images =
[
UIImage.init(color: UIColor.green, size: CGSize(width: 2048, height: 1152))!,
UIImage.init(color: UIColor.green, size: CGSize(width: 2048, height: 1152))!,
UIImage.init(color: UIColor.green, size: CGSize(width: 2048, height: 1152))!,
UIImage.init(color: UIColor.green, size: CGSize(width: 2048, height: 1152))!,
UIImage.init(color: UIColor.green, size: CGSize(width: 2048, height: 1152))!,
]
override func viewDidLoad() {
super.viewDidLoad()
var result = UIImage.init(color: UIColor.blue, size: CGSize(width: 2048, height: 1152))!
for image in images {
//each step reference to previous result released, but memory is growing
result = merge(result, image)
sleep(1)
}
}
public func merge(_ back: UIImage, _ top: UIImage) -> UIImage {
var size = CGSize(width: 2048, height: 1152)
UIGraphicsBeginImageContextWithOptions(size, false, UIScreen.main.scale)
let rec = CGRect(x: 0, y: 0, width: 2048, height: 1152)
back.draw(in: rec)
//multiply is just for example, it can be different blending option
top.draw(in: rec, blendMode: .multiply, alpha: 1)
var newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return newImage
}
}
extension UIImage {
public convenience init?(color: UIColor, size: CGSize) {
let rect = CGRect(origin: .zero, size: size)
UIGraphicsBeginImageContextWithOptions(rect.size, true, 0)
color.setFill()
UIRectFill(rect)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
guard let cgImage = image?.cgImage else {
return nil
}
self.init(cgImage: cgImage, scale: UIScreen.main.scale, orientation: Orientation.up)
}
}
包含虚拟图像和循环的数组。我添加了 sleep 以便在 Instruments
中更好地查看它(没有 sleep 它具有相同的结果)
如你所见,每一秒内存都在增加。
有什么方法可以使每一步的记忆保持在同一水平?
非常感谢!
您可以将合并包装到 autoreleasepool
范围内:
for image in images {
autoreleasepool {
result = merge(result, image)
}
sleep(1)
}
UIKit
将它产生的对象添加到 autoreleasepool
中,以便它们在 运行 循环周期结束时被释放。
我有一组图像,需要使用不同的混合选项合并这些图像。我发现,在此过程中,内存不会在循环的每个步骤中释放。即使没有对创建的图像的引用。在此过程中,我的应用程序崩溃了,因为我有很多图像要合并。有什么解决方法或技巧可以在不增加内存的情况下做到这一点吗? 可以使用以下代码重现:
import UIKit
import CoreImage
class ViewController: UIViewController {
var images =
[
UIImage.init(color: UIColor.green, size: CGSize(width: 2048, height: 1152))!,
UIImage.init(color: UIColor.green, size: CGSize(width: 2048, height: 1152))!,
UIImage.init(color: UIColor.green, size: CGSize(width: 2048, height: 1152))!,
UIImage.init(color: UIColor.green, size: CGSize(width: 2048, height: 1152))!,
UIImage.init(color: UIColor.green, size: CGSize(width: 2048, height: 1152))!,
]
override func viewDidLoad() {
super.viewDidLoad()
var result = UIImage.init(color: UIColor.blue, size: CGSize(width: 2048, height: 1152))!
for image in images {
//each step reference to previous result released, but memory is growing
result = merge(result, image)
sleep(1)
}
}
public func merge(_ back: UIImage, _ top: UIImage) -> UIImage {
var size = CGSize(width: 2048, height: 1152)
UIGraphicsBeginImageContextWithOptions(size, false, UIScreen.main.scale)
let rec = CGRect(x: 0, y: 0, width: 2048, height: 1152)
back.draw(in: rec)
//multiply is just for example, it can be different blending option
top.draw(in: rec, blendMode: .multiply, alpha: 1)
var newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return newImage
}
}
extension UIImage {
public convenience init?(color: UIColor, size: CGSize) {
let rect = CGRect(origin: .zero, size: size)
UIGraphicsBeginImageContextWithOptions(rect.size, true, 0)
color.setFill()
UIRectFill(rect)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
guard let cgImage = image?.cgImage else {
return nil
}
self.init(cgImage: cgImage, scale: UIScreen.main.scale, orientation: Orientation.up)
}
}
包含虚拟图像和循环的数组。我添加了 sleep 以便在 Instruments
中更好地查看它(没有 sleep 它具有相同的结果)
如你所见,每一秒内存都在增加。 有什么方法可以使每一步的记忆保持在同一水平? 非常感谢!
您可以将合并包装到 autoreleasepool
范围内:
for image in images {
autoreleasepool {
result = merge(result, image)
}
sleep(1)
}
UIKit
将它产生的对象添加到 autoreleasepool
中,以便它们在 运行 循环周期结束时被释放。