copy在大数据下不慢,因其底层调用高度优化的runtime.memmove,利用CPU硬件级优化(如缓存行预取、SIMD并行、写合并),使大切片拷贝的单元素成本反低于小切片。

copy 在大数据下不慢,但“慢”常来自误用而非函数本身——它始终只复制 min(len(src), len(dst)) 个元素,且底层调用高度优化的 runtime.memmove,单元素开销随数据量增大反而下降。
为什么大切片 copy 单元素更便宜?
现代 CPU 对连续大块内存移动有硬件级优化:缓存行预取、多路 SIMD 指令并行处理、写合并等。copy 正是利用这点,让 1MB 数据拷贝的平均单字节成本显著低于 1KB 拷贝。这不是错觉,go test -bench 可复现该趋势。
-
copy不做边界检查循环,不逐个赋值,而是交由 runtime 的汇编实现 - 底层数组越连续、越对齐(如
make([]byte, 1),CPU 向量化收益越明显 - 若源/目标切片指向同一底层数组(重叠场景),
copy自动退化为安全的memmove,不额外判断方向
容易被忽略的性能陷阱
真正拖垮性能的不是 copy 本身,而是它前面或后面的配套操作:
- 目标切片
dst用make([]T, len(src))分配 → 触发一次堆分配,比copy本身耗时更长 - 源切片
src是从一个超大底层数组中切出来的(如big[999900:1000000])→copy虽快,但 GC 无法回收整个big数组,内存驻留成本远高于拷贝 - 在 hot path 中反复
make+copy→ 建议复用dst切片(如放在 struct 字段或 sync.Pool 中)
nil 切片和空切片传给 copy 的行为差异
作为源时完全一致:copy(dst, nil) 和 copy(dst, []int{}) 都返回 0,不 panic,也不触发任何内存操作;但作为目标时必须非 nil —— copy(nil, src) 直接 panic: panic: runtime error: cannot slice nil pointer。
- 常见错误:从 map 取值未判空就直接
copy(dst, m[key]),key 不存在时m[key]返回零值nil切片 - 安全写法:
if src, ok := m[key]; ok && len(src) > 0 { copy(dst, src) } - 注意:
[]int{}是有效切片(指针非 nil),可安全作dst;而var s []int是nil,不可作dst
替代方案:什么情况下不该用 copy?
当目标只是“读取一部分内容”且后续不修改时,直接切片比 copy 更轻量:
- 要取前 100 字节:
data[:min(100, len(data))]→ 零分配、零拷贝、共享底层数组 - 要提取字符串子串且需 UTF-8 安全:不能用
copy,改用utf8string.Substring或手动遍历 rune - 要深拷贝嵌套结构(如
[]map[string]interface{}):copy只复制外层 slice 和 map 指针,内部仍共享 → 必须递归 clone
最常被低估的一点:copy 的返回值永远等于实际复制长度,但它不告诉你是否“截断”了。如果业务逻辑依赖完整复制(比如协议解析要求全部字段到位),必须显式校验 n == len(src),否则静默丢数据。











