手动构造的UIViewController内存泄漏无法被Debug Memory Graph检测是什么原因?
根因分析
你构造的UIViewController自循环泄漏是真实存在的,Debug Memory Graph漏检是UIKit特性和工具检测逻辑共同导致的,普通对象没有UIKit的内部缓存机制,所以不会出现这类问题:
- UIKit内部对UIViewController有临时引用缓存,调用
dismiss后系统不会立刻清理控制器的内部关联引用,会延迟到下几个RunLoop周期、页面动画完全结束、视图层级彻底移除后才会释放内部缓存。如果刚dismiss就打开Debug Memory Graph,此时控制器同时被obj = self循环引用+UIKit临时引用持有,工具会误判为控制器仍被系统正常使用,不会标记为泄漏。 - Debug Memory Graph默认开启了系统引用过滤规则,会自动隐藏UIKit内部的引用链,同时会优先过滤掉它判定为「系统正常持有」的对象,漏检自定义的循环引用。
验证&修复检测问题的方法
- 你可以在
Demo类中添加deinit方法打印日志,会发现dismiss后deinit永远不会执行,证明泄漏真实存在,和工具检测结果无关。 - 要让Debug Memory Graph正常识别泄漏,可以在dismiss后等待3~5秒,或触发几次界面交互,等UIKit内部缓存释放后再打开检测工具即可。
- 也可以使用Instruments中的Leaks工具检测,该工具对循环引用的识别敏感度更高,不会出现这类漏检情况。
你提供的测试代码参考:
import UIKit class ViewController: UIViewController { override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { present(Demo(), animated: true, completion: nil) } } class Demo : UIViewController { var obj:Demo? override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .systemTeal obj = self } override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { dismiss(animated: true, completion: nil) } }
相关问题截图:
内容的提问来源于stack exchange,提问作者chdo
相关产品推荐
相关产品推荐

