面试题答案
一键面试切片 append 操作底层内存分配与扩容原理
- 初始分配:
- 当创建一个空切片时,例如
s := make([]int, 0)
,此时切片的容量(cap)为0 。如果执行s = append(s, 1)
,Go 运行时会为切片分配内存。它会根据需要分配一个能容纳至少一个元素的内存块,这个内存块的大小通常会比当前所需的稍大,以减少后续频繁的内存分配。
- 当创建一个空切片时,例如
- 扩容规则:
- 当切片的容量不足以容纳新添加的元素时,就会发生扩容。
- 如果当前切片的容量小于1024 ,那么扩容时新的容量会翻倍。例如,一个切片当前容量为5 ,执行
append
操作导致容量不足,那么新的容量会变为10 。 - 如果当前切片的容量大于或等于1024 ,那么扩容时新的容量会增加当前容量的1/4 。例如,一个切片当前容量为1024 ,执行
append
操作导致容量不足,那么新的容量会变为1024 + 1024/4 = 1280 。
- 内存重新分配:
- 扩容时,Go 运行时会在堆上重新分配一块更大的内存块,这块新内存块的大小由上述扩容规则决定。
- 然后将原切片中的所有元素复制到新的内存块中,接着在新内存块的末尾添加新的元素。
- 最后,更新切片的指针,使其指向新的内存块,同时更新切片的容量和长度。
例如:
package main
import "fmt"
func main() {
s := make([]int, 0, 5)
for i := 0; i < 10; i++ {
s = append(s, i)
fmt.Printf("Length: %d, Capacity: %d\n", len(s), cap(s))
}
}
在上述代码中,初始切片 s
的容量为5 ,随着 append
操作的进行,容量会按照上述规则进行扩容,并输出每次 append
后的长度和容量。