go中传大数组慢是因为按值拷贝整个数组,导致栈溢出或巨量内存分配;而切片[]t仅拷贝24字节头信息,a[:]可零拷贝转为切片。

Go 中传大数组为什么慢?因为默认值拷贝
Go 语言里,[]int 是切片,[1000000]int 是数组——两者类型不同、内存行为完全不同。传一个百万级的 [1000000]int 给函数,编译器会把整个数组内容复制一遍,不是传地址。这不是“性能差”,是直接卡死:栈溢出或巨量内存分配。
- 数组字面量(如
[3]int{1,2,3})和具名数组类型(如type Data [1024*1024]int)都按值传递 - 切片
[]T本质是三元组:ptr+len+cap,传切片只拷贝这 24 字节(64 位系统) - 即使你只读不改,只要参数声明是
func f(a [1000000]int),就逃不开拷贝
什么时候必须用 *[]T?其实几乎不用
*[]T 是“指向切片的指针”,它唯一合理用途是想在函数内 **替换整个切片头**(比如重新 make 或 append 后让调用方看到新底层数组),但这种情况极少。99% 的“想避免拷贝”场景,直接传 []T 就够了——它本来就不拷贝底层数组。
- 错误写法:
func process(data *[1000000]int)→ 还是传数组指针,类型固定、不灵活,且调用时得写&myArray - 正确写法:
func process(data []int),调用方传mySlice即可,零额外开销 - 只有当你真需要修改切片头(例如函数内
data = append(data, x)并希望调用方变量也变),才考虑func f(data *[]int),但通常说明设计有问题
从数组转切片:别用 for 循环复制
如果你手头是个大数组(比如 var a [1000000]int),又想把它交给只接受 []int 的函数,最高效方式是切片转换表达式:a[:]。它不分配新内存,只是生成一个指向原数组首地址的切片头。
- ✅ 正确:
process(a[:])—— 瞬间完成,底层数据零拷贝 - ❌ 错误:
process(append([]int{}, a[:]...))—— 全量复制,内存翻倍,GC 压力陡增 - ⚠️ 注意:
a[:]生成的切片长度和容量都是len(a);若需限制长度,用a[:n](n ≤ len(a))
map[string][1024]byte 这类结构要特别小心
当 map 的 value 是大数组(如 [1024]byte),每次从 map 读取 m[key] 都会拷贝整个数组。哪怕你只读一个字节,Go 也会复制全部 1024 字节。
立即学习“go语言免费学习笔记(深入)”;
- 典型症状:CPU 没跑满,但内存带宽打满,GC 频繁
- 解法一:把 value 改成
*[1024]byte,存指针(注意生命周期,别指向栈变量) - 解法二:改用
[]byte+make([]byte, 1024),再用copy初始化,map 存切片 - 解法三:如果只是固定大小缓冲区,考虑用
sync.Pool复用,避免反复分配
[N]T 和 []T 的根本区别——前者是值,后者是视图。










