在 Swift 中,值类型(如 struct、enum 和 tuple)通常放置在栈上,而引用类型(如 class)则放置在堆上。
栈分配 快速、自动,通常用于存储短生命周期的局部变量。 堆分配 需要更多的开销,通常用于生命周期不确定或大小未知的对象。
示例:
struct Point { var x: Int; var y: Int } let p1 = Point(x: 2, y: 3) // 在栈上 class Node { var value: Int; init(value: Int) { self.value = value } } let n1 = Node(value: 5) // 在堆上
细节:
性能: 栈分配更快,因为不需要处理堆内存和对象生命周期管理。
所有的结构体(struct)是否总是只能放置在栈上?
答案:
不是!虽然结构体是值类型,且通常放在栈上,但编译器可以将它们存储在堆中,如果它们位于类对象、数组、字典中,或者用作闭包中的捕获值。例如:
class Box { var point: Point init(point: Point) { self.point = point } } let box = Box(point: Point(x: 1, y: 2))
在这里,Point 的实例将存储在堆中,因为它属于类 Box。
故事
一个开发人员试图优化结构体的性能,认为大结构体总是会放在栈上,并没有考虑到集合(数组,字典)使用堆分配,这导致项目中内存消耗意外增加。
故事
项目中未考虑到闭包捕获结构体的值,该值被存储在堆中,影响了对象的生命周期。这增加了变量的生命周期并导致了内存泄漏,因为开发者期望它们在超出作用域时自动释放。
故事
在不理解写时复制的情况下使用重结构数组,导致由于在线程之间传递集合而产生意外昂贵的复制操作,降低了性能并导致 UI 延迟。