点击返回按钮后如何减少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
相关产品推荐
相关产品推荐

