Slice 使用误区
假设我们业务代码中用一个切片临时接收外部获得的一个大数据(比如外部API 或 数据库),然后经过逻辑处理后使用 [m:n] 语法取出切片的前10条数据供我们后续使用,那么这个临时的大切片会被 Go 的 GC 后台程序回收掉吗? 下面做一个实验:
示例代码
package main
import (
"fmt"
"runtime"
)
const (
BIG_SLICE_LENGTH = 10000000
SMALL_SLICE_LENGTH = 10
)
func createBigSlice() []int32 {
bigSlice := make([]int32, BIG_SLICE_LENGTH)
for i := 0; i < BIG_SLICE_LENGTH; i++ {
bigSlice[i] = int32(i)
}
fmt.Printf("big slice length %d, cap %d\n", len(bigSlice), cap(bigSlice))
return bigSlice
}
func createSmallFromBig() []int32 {
bigSlice := createBigSlice()
smallSlice := bigSlice[:SMALL_SLICE_LENGTH]
return smallSlice
}
func main() {
small := createSmallFromBig()
runtime.GC()
fmt.Printf("big slice length %d, cap %d\n", len(small), cap(small))
}
在控制台的输出结果是:
big slice length 10000000, cap 10000000
big slice length 10, cap 10000000
可以看到,我们在函数内部临时创建的大切片,依然在调用 Go 的 GC 完成之后,还依然存在。
借助 IDE 的 debug 工具可以更直观的验证

首先可以看到我们确实取出了大切片的前10条数据,但是 cap 字段显示了,我们这个小切片的底层数组依然是旧的。
我们来验证一下,首先找到下标9的数据地址

然后在这个地址的基础上+4看看(一个int32占4字节)

我们依然取出了大数组的下标10的数据
所以,以后如果用 [m:n] 方法复用切片的时候要注意内存泄漏的问题。