CAMetalLayer.nextDrawable耗时过长问题排查(附测试代码)
CAMetalLayer.nextDrawable() 异常高耗时问题复现
CAMetalLayer.nextDrawable() 本应是低耗时方法,但实际场景中偶尔会出现耗时超过8ms的情况,可通过以下步骤复现问题:
- 复制下方Swift代码
- 按照代码中
viewDidLoad方法内的注释指引操作 - 查看控制台日志输出
class TestVC: UIViewController { let metalLayer:CAMetalLayer = CAMetalLayer() var displayLink:CADisplayLink! var thread:Thread! var animationView:AnimationView! override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { self.displayLink.isPaused = true } override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { self.displayLink.isPaused = false } override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() print("ahhhaa") } override func viewDidLoad() { super.viewDidLoad() self.view.backgroundColor = .red let scale = UIScreen.main.scale metalLayer.frame = self.view.bounds metalLayer.drawableSize = CGSize(width: self.view.frame.width * scale, height: self.view.frame.height * scale) self.view.layer.addSublayer(metalLayer) self.addDisplayLinkInUITaskRunner() // 等待页面加载完成后,可执行以下操作: // 1. 下拉控制中心,控制台会持续输出大量日志 // 2. 将应用切换到后台再切回前台,控制台会输出大量日志,且会持续较长时间 // 3. 不进行任何操作,也可能会看到日志持续输出.... // 点击屏幕后日志可能消失,但一段时间后可能再次出现.... } func addDisplayLinkInUITaskRunner() { self.thread = Thread(block: { RunLoop.current.add(NSMachPort(), forMode: .common) RunLoop.current.run() }) self.thread.name = "" self.thread.start() self.perform(#selector(addDisplayLink), on: thread, with: nil, waitUntilDone: false) } @objc func addDisplayLink() { self.displayLink = CADisplayLink(target: self, selector: #selector(onDisplayLink)) if #available(iOS 15.0, *) { self.displayLink.preferredFrameRateRange = .init(minimum: 60, maximum: 120, preferred: 120) } else { self.displayLink.preferredFramesPerSecond = 120 } self.displayLink.add(to: .current, forMode: .common) } @objc private func onDisplayLink() { let startTime = CACurrentMediaTime() let frameDrawable = metalLayer.nextDrawable()! let timeUsed = CACurrentMediaTime() - startTime // 获取next drawable耗时超过5ms时,打印日志标记该方法耗时过长 if (timeUsed > 0.005) { print("CAMetalLayer.nextDrawable take much time!! -> \(String(format: "%.2f", timeUsed * 1000)) ms") } frameDrawable.present() } }
内容的提问来源于stack exchange,提问作者luckysmg
相关产品推荐
相关产品推荐

