append 性能损耗

未指定长度或者长度不足时,双倍扩容(cap < 1024); 1.25倍扩容(cap > 1024)。把元内存空间的数据拷贝过来,然后在新的内存空间继续append数据

在 Go 1.18 以后,扩容使用threshold为临界点(源码中设置为256)
当slice容量 < 256时, 每次扩容为原来的两倍。当slice容量 > 256时, 每次增加(oldcap + 3*threshold) 3/4

母子切片共享内存问题

1
2
slicem := make([]int, 3, 5) // len = 3, cap = 5 分配了5个空间,置入了3个数据
slices := slicem[1:3] // len = 2, cap = 4

最开始时,子切片和母切片共享母切片的内存空间,对子切片的修改会反映到母切片上,对子切片的 append 操作,会将数据添加到母切片预留的内存空间内。
如持续进行 append 操作,直到将母切片预留的内存空间完全消耗完毕后,二者就会发生内存分离,从此再无关系

切片导致内存泄漏

1
2
3
4
5
func Leak() []int {
parent := make([]int, 0, 100)
son := parent[10:20]
return son
}

func 返回子切片,只要这个子切片没有被 GC 回收,子切片持有的母切片的内存空间就得不到释放,导致泄漏

函数参数需要用切片指针么

如果函数内部需要对切片的 len 和 cap 进行修改,且修改要反映在函数外部,那么需要传入切片的指针

一边遍历一边修改切片

1
2
3
4
5
6
7
8
9
10
arr := []int{1,2,3}
// go 中 for-range 遍历的是原集合的拷贝
for i, m := range arr {
m += 1
}

// 下方这种才能修改成功
for i, m := range arr {
arr[i] = m + 1
}