簡體   English   中英

使用Metal的舊設備的內存使用率不斷上升

[英]Memory usage keeps rising on older devices using Metal

我使用MetalCADisplayLink實時過濾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圖總是在增長:

Xcode中

分配

更新2:附加按大小排序的分配列表的屏幕截圖,應用程序運行16分鍾,應用過濾器不停止:

在此輸入圖像描述

更新3:有關applyAnimatedFilter()發生的事情的更多信息:

我將過濾后的圖像渲染到一個metalViewMTKView 我從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
    }

}

以下是一些觀察,但我不確定其中一個是否真正導致您看到的內存使用情況:

  • applyFilter每幀都要創建一個新的ColorMix過濾器。 另外,在實例方法中use(image:, time:)你在每次調用時都會創建另一個 這是一個很大的開銷,特別是因為過濾器每次都在init上加載它的內核。 建議在安裝過程中創建一個ColorMix過濾器,並在每一幀上更新其inputImageinputTime
  • outputImage不是一個func ,而是一個從CIFilter超類重寫的var

    override var outputImage: CIImage? { /* your code here */ }

  • 你的colorMix內核是否colorMix執行任何類型的卷積? 如果沒有,它可能是CIColorKernel而不是。

  • 如果您需要內核中輸入的大小,則不需要將其作為額外參數傳遞。 您只需在輸入sampler上調用.size()

這是Xcode診斷功能(金屬驗證和/或GPU幀捕獲)中的一個錯誤。 如果關閉它們,內存使用量應與在Xcode外部運行時類似。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM