当“值语义的复制成本”
大于“引用语义的 ARC 成本”时,
struct 会比 class 慢,而且可能慢很多。
下面我用 真实可遇到的场景 给你拆。
一、真实场景 1:大 struct + 频繁传参(最常见)
❌ struct 翻车版本
struct Packet {
var header: Header
var payload: [UInt8] // 很大
var checksum: Int
}
func process(_ p: Packet) {
// 只读
}
for packet in packets {
process(packet)
}
为什么慢?
-
Packet是值类型 -
每次
process(packet)都是 值传递 -
payload 是大数组 → CoW
-
一旦
process或更深层出现写操作:- 整个 payload 被复制
哪怕你“以为”只读。
✅ class 版本更快
final class Packet {
var header: Header
var payload: [UInt8]
var checksum: Int
}
- 只传一个指针
- 没有 CoW
- ARC 成本 < 大内存复制
👉 在“大对象 + 深调用栈”中,class 胜
二、真实场景 2:struct 在集合中频繁修改
❌ struct in Array
struct Node {
var x: Int
var y: Int
var data: [Float] // 非常大
}
var nodes = loadMillionNodes()
for i in nodes.indices {
nodes[i].x += 1
}
问题
-
nodes是 Array(本身 CoW) -
Node是 struct -
修改一个字段:
- 整个
Node被 copy - 内部 data 触发 CoW
- 整个
👉 你只改了 x,却搬了整栋楼
class 版本
final class Node {
var x: Int
var y: Int
var data: [Float]
}
for node in nodes {
node.x += 1
}
- 原地修改
- 没有元素级拷贝
- cache 更友好
三、真实场景 3:struct + protocol existential
❌ struct + any Protocol
protocol Renderable {
func render()
}
struct Sprite: Renderable {
var buffer: [UInt8]
}
let items: [any Renderable] = sprites
性能问题
- struct 被 装箱(existential container)
- buffer 不再 inline
- 访问变成间接
class:
- 本来就是引用
- 没有额外装箱
👉 struct 的优势在 existential 下直接消失
四、真实场景 4:struct 在并发环境中被频繁复制
struct Frame {
var pixels: [UInt8] // 4MB
}
let frame = loadFrame()
DispatchQueue.concurrentPerform(iterations: 4) { _ in
process(frame)
}
发生了什么?
- 每个线程拿到一个“值”
- 第一次写 → 各自复制 4MB
- 内存带宽被打爆
class:
- 多线程共享引用
- 只复制必要的数据
五、真实场景 5:struct 尺寸过大(cache miss)
经验阈值(非硬规则)
struct 超过 64–128 bytes,
就要开始怀疑性能了。
原因:
- 函数参数传递
- cache line 填充
- memcpy 成本
class:
- 永远只传 8 bytes 指针
六、真实场景 6:struct 被当“可变对象”使用
struct State {
var a: Int
var b: Int
var c: Int
}
func update(_ state: inout State) {
state.a += 1
state.b += 1
}
在小规模下没问题,但如果:
- State 里有大字段
- update 被频繁调用
👉 struct 在被“当 class 用”时,一定慢
七、为什么这些场景 class 更快?
一句话:
struct 的性能优势来自“不可变 + 小 + 本地化”,
一旦违背其中任意一条,优势就会迅速消失。
而 class 的优势是:
- 稳定
- 可预测
- 修改成本固定
八、一个实战判断表(非常有用)
| 场景 | 更优选择 |
|---|---|
| 小对象 / 不可变 | struct |
| 大对象 / 可变 | class |
| 并发共享 | class |
| 热路径频繁修改 | class |
| protocol existential | class |
| SwiftUI / 值流 | struct |
| 算法核心 | struct(小) |
九、一句话结论(送你)
struct 是“快的前提条件更多”,
class 是“慢得更稳定”。