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

为何预期存在Retain Cycle的代码未被Instruments检测到内存泄漏?

为什么预期的循环引用内存泄漏没有出现?

我在学习**Retain Cycle(循环引用)**时编写了一段理论上会产生内存泄漏的代码,但使用Instruments工具检测后并未发现泄漏。

相关代码如下:

import UIKit

class ViewController: UIViewController {

    private var button = {
        let _button = UIButton()
        _button.setTitle("Tap Me", for: .normal)
        _button.setTitleColor(.systemBlue, for: .normal)
        return _button
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.addSubview(button)
        
        button.addTarget(self, action: #selector(actionButton), for: .touchUpInside)
        
        button.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            button.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            button.centerYAnchor.constraint(equalTo: view.centerYAnchor),
            button.widthAnchor.constraint(equalToConstant: 80),
            button.heightAnchor.constraint(equalToConstant: 30)
        ])
    }
    
    @objc private func actionButton() {
        
        let secondVC = ViewController2()
        
        present(secondVC, animated: true)
    }

}

class MyView: UIView {
    
    let viewContoller: ViewController2
    
    init(from vc: ViewController2) {
        viewContoller = vc
        
        super.init(frame: .zero)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
}

class ViewController2: UIViewController {
    
    var myView: MyView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = .red
        
        myView = MyView(from: self)
    }
    
}

代码逻辑:点击ViewController的按钮会弹出ViewController2,ViewController2会初始化持有自身引用的MyView,按道理关闭ViewController2时应该形成循环引用,但实际ViewController2的deinit方法能正常执行,Instruments也显示无泄漏,想知道问题出在哪里?


问题解析:循环引用未被外部强持有,ARC自动回收

循环引用导致内存泄漏的核心前提是:循环中的对象被外部强引用持有,当外部引用释放后,循环内的对象因互相强引用无法被回收。

你的代码里确实存在双向强引用:

  • ViewController2通过var myView: MyView!强持有MyView
  • MyView通过let viewContoller: ViewController2强持有ViewController2

但关键在于,当你关闭ViewController2时,present它的ViewController会释放对ViewController2的强引用,此时整个循环(ViewController2 + MyView)没有被任何外部对象强持有。ARC会识别到这组对象不再被任何代码需要,会将它们全部销毁,因此不会产生内存泄漏。

如何制造真正的内存泄漏

如果要让这段代码产生预期的泄漏,只需让循环被外部强引用持有即可。比如修改ViewController,让它持有ViewController2的引用:

class ViewController: UIViewController {
    private var secondVC: ViewController2? // 新增外部强引用
    
    @objc private func actionButton() {
        secondVC = ViewController2()
        present(secondVC!, animated: true)
    }
}

此时关闭ViewController2后,ViewController仍然持有secondVC的强引用,而secondVC和MyView互相引用,即使dismiss了ViewController2,它也无法被销毁,Instruments就能检测到内存泄漏。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 18:33:10