- 结构定义
slice是由一个指针和两个属性组成,指针指向内存的起始位置,len是数据的填充数量,cap是当前情况下能够容纳的所有数据的容量。slice.go中有8个函数
growslice:切片扩容函数
isPowerOfTwo :判断一个数是否是2的幂(风骚的写法)
makeslice :切片初始化
makeslice64 : 切片初始化:
slicecopy :切片拷贝
slicestringcopy:切片拷贝
type slice struct {
array unsafe.Pointer
len int
cap int
}
2.内存分配
slice内存分配是调用了malloc
中的mallocgc
函数,内存分配分两种情况,大于32kb的时候直接在堆中分配内存,小于32kb的小对象直接在free list中分配.
slice 能够分配的理论大小
3.切片操作
对一个数组进行切片,新的切片不会申请新的内存,只会把新的指针变量指向原来的内存空间,换句话说切片只是一个特殊的带有两个变量的指针,我们对切片的操作不会导致内存空间的剧烈变化,这样的设计确保的高效迅速,[1]
但是有点小坑还会要注意的,如果现在有多个切片,他们都指向的同一个数据内存,如果其中一个变化了,那么另外一个也会跟着变化。
4.扩容
当len > cap的时候会触发扩容操作,golang中对扩容也进行了简单的判断,如果现在切片的长度小于1024那么当容量不够、需要重新申请内存的时候直接申请内存的两倍,也就是cap *2 ,但是当cap > 1024的时候,此时如果直接申请1024可能会导致很大的空间被浪费,这时候重新申请内存是原来内存的1.25倍,也就是cap * 1.25。同时要注意的是当新的容量大于两倍的之前的容量的时候,比如原来切片长度为5,现在往里添加了1000个长度,这个时候不会不断的扩容去适应这个长度,而是直接把1000+5赋值给新的切片容量。扩容设计到数组的拷贝工作,要实现原来内存的额“举家搬迁”,所以在初始化的时候尽量给切片一个合适的初始容量能够避免前期的数组频繁拷贝。