You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

点击返回按钮后如何减少ARKit场景的App内存消耗(避免泄漏)

解决ARKit场景返回后内存泄漏的问题

你遇到的是ARKit资源未彻底释放导致的内存累积问题——每次打开ARViewController创建的AR会话、场景节点及关联资源,在返回时没被清理,一直占用内存,重复打开就会持续增加消耗。下面是具体的修复方案:

核心修复步骤

1. 停止AR会话并断开视图关联

ARSession在后台会持续占用内存和处理器资源,必须在ViewController即将消失时停止会话,同时断开ARSCNView的关联,避免潜在引用:

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    // 暂停AR会话
    session.pause()
    // 断开sceneView与会话的绑定
    sceneView.session = nil
    // 置空代理,消除循环引用风险
    sceneView.delegate = nil
}

2. 彻底清理场景节点

你在setupFocusSquare里处理了旧的聚焦方块,但在ViewController销毁时,需要移除所有自定义添加的节点,避免它们持有视图引用:

private func cleanUpSceneNodes() {
    // 移除并置空focusSquare
    focusSquare?.removeFromParentNode()
    focusSquare = nil
    // 遍历移除根节点下所有子节点(如果有其他自定义节点的话)
    sceneView.scene.rootNode.enumerateChildNodes { node, _ in
        node.removeFromParentNode()
    }
}

3. 清理TextManager的定时任务

textManager的定时消息如果没取消,可能会持有ARViewController的引用,导致无法被释放,需要在清理时取消所有待发送的消息:

private func cleanUpTextManager() {
    textManager.cancelAllScheduledMessages()
    // 如果textManager是自定义对象,也可以直接置空引用
    // textManager = nil
}

4. 添加deinit验证释放状态

添加deinit方法可以帮你确认ViewController是否被成功销毁,如果控制台没打印日志,说明还存在循环引用:

deinit {
    print("ARViewController has been deinitialized")
}

整合后的完整代码片段

把上述步骤整合到你的ARViewController中:

class ARViewController: UIViewController, ARSCNViewDelegate {
    // 假设你已声明以下属性
    var session: ARSession!
    var sceneView: ARSCNView!
    var focusSquare: FocusSquare?
    var textManager: TextManager!

    override func viewDidLoad() {
        super.viewDidLoad()
        setupScene()
        setupFocusSquare()
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        // 清理ARKit核心资源
        session.pause()
        sceneView.session = nil
        sceneView.delegate = nil
        
        // 清理场景节点
        cleanUpSceneNodes()
        
        // 清理TextManager任务
        cleanUpTextManager()
    }

    func setupScene() {
        sceneView.delegate = self
        sceneView.session = session
        sceneView.antialiasingMode = .multisampling4X
        sceneView.automaticallyUpdatesLighting = false
        sceneView.preferredFramesPerSecond = 60
        sceneView.contentScaleFactor = 1.3
        enableEnvironmentMapWithIntensity(25.0)
        if let camera = sceneView.pointOfView?.camera {
            camera.wantsHDR = true
            camera.wantsExposureAdaptation = true
            camera.exposureOffset = -1
            camera.minimumExposure = -1
            camera.maximumExposure = 3
        }
    }

    func setupFocusSquare() {
        focusSquare?.isHidden = true
        focusSquare?.removeFromParentNode()
        focusSquare = FocusSquare()
        sceneView.scene.rootNode.addChildNode(focusSquare!)
        textManager.scheduleMessage("TRY MOVING LEFT OR RIGHT", inSeconds: 5.0, messageType: .focusSquare)
    }

    private func cleanUpSceneNodes() {
        focusSquare?.removeFromParentNode()
        focusSquare = nil
        sceneView.scene.rootNode.enumerateChildNodes { node, _ in
            node.removeFromParentNode()
        }
    }

    private func cleanUpTextManager() {
        textManager.cancelAllScheduledMessages()
    }

    deinit {
        print("ARViewController has been deinitialized")
    }
}

额外检查点

  • 确保FocusSquare或其他自定义节点没有持有ARViewController的强引用(比如闭包要使用[weak self])
  • 如果enableEnvironmentMapWithIntensity加载了外部资源(如环境贴图),也要确保这些资源在清理时被释放
  • 可以用Xcode的Memory Graph Debugger检查内存泄漏的具体对象,定位未被释放的引用链

内容的提问来源于stack exchange,提问作者Kalpesh Prajapati

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 07:32:11