一、CoW 的核心假设(先记住)
绝大多数副本是只读的,
写入是少量、可控、集中发生的。
一旦现实不满足这个假设,CoW 就会崩。
二、最常见的 CoW 性能灾难场景
1️⃣ “读-写交错”的大数组流水线
var data = loadHugeArray()
for x in data {
if shouldModify(x) {
data.append(transform(x))
}
}
问题在哪里?
-
data被遍历(只读视图) -
同时又被写
-
每一次写:
- iterator 仍然活着
- Swift 必须复制整个 buffer
-
多次 CoW = O(n²)
👉 这是 CoW 最经典的反例
2️⃣ 频繁的小写操作作用于“大数据”
var a = bigArray
for i in 0..<1000 {
a[i] += 1
}
看起来只是 1000 次写?
实际上:
a与原数组共享 buffer- 第一次写 → 整块数组复制
- 拷贝成本 ≈
bigArray.count
👉 写次数少 ≠ 拷贝成本低
3️⃣ CoW + 多层函数传参
func step1(_ a: [Int]) { step2(a) }
func step2(_ a: [Int]) { step3(a) }
func step3(_ a: [Int]) {
var b = a
b.append(1)
}
隐藏成本
-
多层函数都在“共享同一个 buffer”
-
在最深层写入时:
- Swift 发现 owner 数量很多
- 复制成本最高
👉 越晚写,越贵
4️⃣ 多线程 / 并发下的 CoW
let shared = bigArray
DispatchQueue.concurrentPerform(iterations: 4) { _ in
var local = shared
local.append(1)
}
发生了什么?
-
每个线程:
- 第一次写都要 copy
-
内存带宽被打满
-
cache line 频繁失效
👉 CoW 在并发下是“复制风暴”
5️⃣ Dictionary / Set 高频更新
var dict = bigDict
for k in keys {
dict[k] = compute(k)
}
隐患
- 哈希表本身很大
- 每次首次写都要整表复制
- rehash + copy
👉 CoW 对 hash 表比 Array 更伤
6️⃣ 隐式写操作(最阴险)
表面“只读”
let b = a.map { $0 }
实际
- 新 array
- 新 buffer
- 立即分配
或者:
array.sort() // 写
array.sorted() // 分配 + 拷贝
👉 很多 API 名字不明显
7️⃣ CoW + 桥接(Swift ↔ Objective-C)
let ns = swiftArray as NSArray
swiftArray.append(1)
问题
- 桥接会固定 buffer
- Swift 不再能“就地优化”
- 写入必复制
👉 桥接会“冻结”CoW 优化路径
三、为什么 Objective-C 在这些场景反而更快?
Objective-C 的模型是:
可变就是可变,没有隐式复制
[mutableArray addObject:x];
- 原地修改
- 没有“突然整块复制”的惊吓
- 性能更可预测
👉 大规模、频繁写入 = ObjC 更稳
四、如何避免 CoW 成为瓶颈(实战建议)
✅ 1. 尽早“断开共享”
var a = original
a.reserveCapacity(original.count + extra)
- 提前触发一次 CoW
- 后续写都是 cheap
✅ 2. 分离读写集合
let source = array
var target = array
target.removeAll(keepingCapacity: true)
for x in source {
target.append(process(x))
}
✅ 3. 写入前 ensureUnique(概念)
Swift 标准库内部做了:
isKnownUniquelyReferenced(&buffer)
你在自己封装 buffer 时也应这么做。
✅ 4. 大数据 + 高频写:慎用值语义
在这些场景下:
- class
- NSMutableArray
- UnsafeBufferPointer
反而是正确工具。
五、一个判断 CoW 会不会拖慢你的经验法则
如果你的代码满足 任意两条,就要警惕 CoW:
- 数据量很大
- 写操作不是一次性的
- 写发生在深层调用
- 写发生在并发环境
- 写操作“看起来很少”
六、一句话结论(记住它)
CoW 擅长“少写多读”,
但讨厌“偷偷写”和“反复写”。