为什么Swift不使用传统的垃圾回收器?
\n如果你是从Python或Java的世界来到Swift,你可能会惊讶地发现,这门语言没有传统的垃圾回收器(Garbage Collector)。相反,Apple引入了一种称为自动引用计数(Automatic Reference Counting,ARC)的机制。这并非一时兴起:在移动设备上,每一个CPU时钟周期和每一字节内存都弥足珍贵。传统的GC在回收时会“冻结”应用程序,这对于要求动画流畅(60 FPS)的iOS来说将是一场灾难。
\n在本文中,我们将探讨Swift中内存管理的实际工作原理,循环引用可能隐藏的陷阱,以及如何编写不会“泄漏”内存的代码。
\n\nARC:底层是如何工作的?
\nARC并非传统意义上的垃圾回收器。它在编译阶段工作:编译器在适当的位置插入retain和release指令。但有一个问题:ARC无法处理循环引用(retain cycles)。如果两个对象通过强引用相互持有,它们的引用计数永远不会降为零——内存就会泄漏。
示例:简单的类与引用计数
\nclass Person {\n let name: String\n init(name: String) {\n self.name = name\n print("\\(name) 出现在内存中")\n }\n deinit {\n print("\\(name) 从内存中消失")\n }\n}\n\nvar person1: Person? = Person(name: "Alice") // retain count = 1\nvar person2 = person1 // retain count = 2\nperson1 = nil // retain count = 1\nperson2 = nil // retain count = 0 → deinit\n\n在控制台中,你会看到:“Alice 出现在内存中”,过一会儿后:“Alice 从内存中消失”。一切正常。
\n\n循环引用:内存的头号敌人
\n想象一下:你有一个User和一个Account。用户拥有一个账户,而账户知道它的所有者。如果两个属性都是强引用,就会形成一个闭环:
class User {\n let name: String\n var account: Account?\n init(name: String) { self.name = name }\n deinit { print("User \\(name) 已删除") }\n}\n\nclass Account {\n let number: String\n var owner: User?\n init(number: String) { self.number = number }\n deinit { print("Account \\(number) 已删除") }\n}\n\nvar user: User? = User(name: "Boris")\nvar account: Account? = Account(number: "12345")\nuser?.account = account\naccount?.owner = user\n\nuser = nil // User 未被删除!account?.owner 仍然持有引用\naccount = nil // Account 未被删除!user?.account 持有引用\n// 内存泄漏!\n\n控制台中不会出现任何deinit消息。对象永远停留在内存中。这就是retain cycle——Swift中内存管理的经典问题。
如何解决?Weak和Unowned
\n解决方案是将其中一个引用设为弱引用(weak)或无主引用(unowned)。区别如下:
- \n
- weak — 始终是可选类型,当对象被删除时自动变为
nil。安全。 \n - unowned — 非可选类型,假定对象的生命周期更长。如果访问已删除的对象,会导致崩溃。 \n
class Account {\n let number: String\n weak var owner: User? // ← 弱引用\n init(number: String) { self.number = number }\n deinit { print("Account \\(number) 已删除") }\n}\n// 现在 user = nil 会释放 User,而 account?.owner 会变为 nil\n\n\n垃圾回收器 vs ARC:哪个更快?
\n说实话:ARC并非传统意义上的“垃圾回收器”。真正的GC(如Java、Go或Python中的)在运行时工作:它会定期扫描堆,找到不可达的对象并释放它们。这需要暂停(stop-the-world)。
\n而ARC是一种静态