Go语言切片的扩容机制
- 基本原理:
- Go语言的切片(slice)底层是基于数组实现的动态数组。当切片容量不足以容纳新的元素时,就会发生扩容。
- 扩容时,Go会创建一个新的更大的底层数组,将原切片的内容复制到新数组中,然后原切片指向新的底层数组。
- 扩容策略:
- 如果新的元素个数小于等于当前切片容量的两倍,且当前切片容量小于1024,则新的容量会扩展为当前容量的两倍。
- 如果当前切片容量大于等于1024,则新的容量会扩展为当前容量的1.25倍。
- 如果新的元素个数大于当前切片容量的两倍,则新的容量会直接设置为新的元素个数。
避免频繁切片扩容带来性能问题的方法及示例
- 预先分配足够的容量:
- 在创建切片时,通过
make
函数指定合适的容量,这样可以避免在添加元素过程中频繁扩容。
- 示例:
package main
import (
"fmt"
)
func main() {
// 预先分配容量为100的切片
s := make([]int, 0, 100)
for i := 0; i < 100; i++ {
s = append(s, i)
}
fmt.Println(s)
}
- 在上述示例中,通过
make([]int, 0, 100)
预先分配了容量为100的切片,在添加100个元素的过程中不会发生扩容,提升了性能。
- 使用
cap
函数判断是否需要扩容:
- 在添加元素之前,使用
cap
函数检查切片的容量是否足够。如果不够,提前手动扩容,避免在append
时自动扩容导致性能损耗。
- 示例:
package main
import (
"fmt"
)
func main() {
s := make([]int, 0, 5)
for i := 0; i < 10; i++ {
if cap(s)-len(s) < 1 {
newS := make([]int, len(s), cap(s)*2)
copy(newS, s)
s = newS
}
s = append(s, i)
}
fmt.Println(s)
}
- 在这个示例中,每次添加元素前,检查切片的剩余容量是否小于1,如果小于1,则手动将切片容量扩大为原来的两倍,从而减少自动扩容带来的性能开销。