Go语言是否对切片操作的复用进行内存优化?
Go切片重复操作的内存占用与底层数组共享问题
首先明确结论:对同一个基础切片执行相同的切片操作时,两次得到的切片会共享同一个底层数组,不会创建独立的底层数组副本,内存占用在底层数组层面完全一致。
为什么会这样?
Go的切片本质是一个包含三个字段的结构体:
- 指向底层数组的指针
- 切片的长度(len)
- 切片的容量(cap)
每次执行a[:4]这类切片操作时,会生成一个新的切片结构体,但这个结构体里的指针会直接指向原切片底层数组的对应起始位置(这里是原数组的第0个元素)。也就是说,底层数组完全复用,不会有新的内存分配,只是多了一个轻量的切片结构体(64位系统下仅占24字节:8字节指针+8字节len+8字节cap)。
验证方法(解决无法直接取切片地址的问题)
虽然直接对a[:4]取地址会报错(临时值不可寻址),但可以通过以下方式验证底层数组的共享性:
package main import "fmt" func main() { a := make([]int, 10) // 将切片操作结果赋值给变量 s1 := a[:4] s2 := a[:4] // 打印底层数组的起始地址(通过切片第一个元素的地址) fmt.Printf("s1底层数组起始地址: %p\n", &s1[0]) fmt.Printf("s2底层数组起始地址: %p\n", &s2[0]) // 打印切片结构体自身的地址(两个结构体独立,但不影响底层数组) fmt.Printf("s1切片结构体地址: %p\n", &s1) fmt.Printf("s2切片结构体地址: %p\n", &s2) }
运行这段代码会看到,s1和s2的底层数组起始地址完全相同,证明它们共享同一个底层数组;而切片结构体的地址不同,只是因为每次切片操作生成了新的结构体实例,但这种内存开销可以忽略不计。
回到你的代码场景
在你的代码中:
a := make([]int, 10) log.Msgf("the subarray is: %v", a[:4]) return a[:4]
日志中的a[:4]和返回值的a[:4]是两个独立的切片结构体,但它们指向的是同一个底层数组,不会导致底层数组的内存被重复占用。编译器不会优化掉这两个切片结构体,但这种轻量级的内存开销在实际场景中几乎可以忽略。
内容的提问来源于stack exchange,提问作者Ivasan
相关产品推荐
相关产品推荐

