【发布时间】:2019-11-13 05:55:46
【问题描述】:
我使用Metal 和CADisplayLink 实时过滤CIImage 并将其渲染为MTKView。
// Starting display link
displayLink = CADisplayLink(target: self, selector: #selector(applyAnimatedFilter))
displayLink.preferredFramesPerSecond = 30
displayLink.add(to: .current, forMode: .default)
@objc func applyAnimatedFilter() {
...
metalView.image = filter.applyFilter(image: ciImage)
}
根据 Xcode 中的内存监视器,内存使用量在 iPhone X 上是稳定的,不会超过 100mb,在 iPhone 6 或 iPhone 6s 等设备上,内存使用量一直在增长,直到最终系统终止应用程序。
我已经使用Instruments 检查了内存泄漏,但没有报告泄漏。通过分配运行应用程序也不会显示任何问题,并且应用程序不会被系统关闭。我还发现有趣的是,在较新的设备上,内存使用是稳定的,但在较旧的设备上,它只会不断增长。
过滤器的复杂性并不重要,因为我尝试了最简单的过滤器,但问题仍然存在。这是我的金属文件中的一个示例:
extern "C" { namespace coreimage {
float4 applyColorFilter(sample_t s, float red, float green, float blue) {
float4 newPixel = s.rgba;
newPixel[0] = newPixel[0] + red;
newPixel[1] = newPixel[1] + green;
newPixel[2] = newPixel[2] + blue;
return newPixel;
}
}
我想知道是什么原因导致旧设备出现问题,以及我应该朝哪个方向努力。
更新 1:这里有两张 1 分钟图,一张来自Xcode,一张来自Allocations,两者都使用相同的过滤器。 Allocations 图表稳定,而Xcode 图表一直在增长:
更新2:附上按大小排序的分配列表截图,应用运行了16分钟,不停地应用过滤器:
更新 3:更多关于 applyAnimatedFilter() 中发生的事情的信息:
我将过滤后的图像渲染为metalView,即MTKView。我从filter.applyFilter(image: ciImage) 收到过滤后的图像,接下来在Filter 中发生:
func applyFilter(image: ciImage) -> CIImage {
...
var colorMix = ColorMix()
return colorMix.use(image: ciImage, time: filterTime)
}
filterTime 只是一个 Double 变量。最后,这是整个 ColorMix 类:
import UIKit
class ColorMix: CIFilter {
private let kernel: CIKernel
@objc dynamic var inputImage: CIImage?
@objc dynamic var inputTime: CGFloat = 0
override init() {
let url = Bundle.main.url(forResource: "default", withExtension: "metallib")!
let data = try! Data(contentsOf: url)
kernel = try! CIKernel(functionName: "colorMix", fromMetalLibraryData: data)
super.init()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func outputImage() -> CIImage? {
guard let inputImage = inputImage else {return nil}
return kernel.apply(extent: inputImage.extent, roiCallback: {
(index, rect) in
return rect.insetBy(dx: -1, dy: -1)
}, arguments: [inputImage, CIVector(x: inputImage.extent.width, y: inputImage.extent.height), inputTime])
}
func use(image: CIImage, time: Double) -> CIImage {
var resultImage = image
// 1. Apply filter
let filter = ColorMix()
filter.setValue(resultImage, forKey: "inputImage")
filter.setValue(NSNumber(floatLiteral: time), forKey: "inputTime")
resultImage = filter.outputImage()!
return resultImage
}
}
【问题讨论】:
-
您是否尝试添加自动释放池?
-
@matt 我没有,我认为它在仅 Swift 的项目中作用不大?
-
好吧,你想错了。 :) 我不保证它会解决这个特殊问题,但至少让我们尝试一下。将
applyAnimatedFilter的整个内部包裹在autoreleasepool块中,让我们看看是否有什么不同。 -
@matt 谢谢,我现在就试试 :) 另外我注意到,当通过 Instruments 在 Allocations 上运行应用程序时,它不会被杀死并且内存图是稳定的。 Xcode 和 Instruments 在内存管理上会不会有什么不同?
-
@matt 根据 Xcode 内存图添加
autireleasepool没有影响
标签: ios swift metal core-image cadisplaylink