Go - array、slice

2021-05-13  本文已影响0人  kyo1992

array

特征
初始化
arr1 := [3]int{1, 2, 3}
arr2 := [...]int{1, 2, 3}
特殊点

在不考虑逃逸分析的情况下,如果数组中元素的个数小于或者等于 4 个,那么所有的变量会直接在栈上初始化,如果数组元素大于 4 个,变量就会在静态存储区初始化然后拷贝到栈上

slice

结构
type SliceHeader struct {
    Data uintptr
    Len  int
    Cap  int
}

Data 指向一片连续的内存空间,切片可以理解成一片连续的内存空间加上长度与容量的标识。

初始化
arr[0:3] or slice[0:3]
slice := []int{1, 2, 3}
slice := make([]int, 10)

如果当前的切片不会发生逃逸并且切片非常小(<5)的时候,会在栈上分配内存; 如果切片长度较大,或者发生内存逃逸,则会在堆上进行内存分配。

追加与扩容

追加时,当切片的容量不足,发生扩容, 为切片分配新的内存空间并拷贝原切片中元素.

扩容策略

  1. 如果期望容量大于当前容量的两倍就会使用期望容量;
  2. 如果当前切片的长度小于 1024 就会将容量翻倍;
  3. 如果当前切片的长度大于 1024 就会每次增加 25% 的容量,直到新容量大于期望容量;
  4. 当数组中元素所占的字节大小为 1、8 或者 2 的倍数时,运行时会使用代码对齐内存, 获取的内存数量可能会稍微增多,提高内存的分配效率并减少碎片。

append结果会返回一个新的切片,其中包含了新的数组指针、大小和容量,这个返回的三元组最终会覆盖原切片

代码分析
var arr []int64
arr = append(arr, 1, 2, 3, 4, 5)

当我们执行上述代码时,会触发 runtime.growslice 函数扩容 arr 切片并传入期望的新容量 5,这时期望分配的内存大小为 40 字节;不过因为切片中的元素大小等于 sys.PtrSize,所以运行时会调用 runtime.roundupsize 向上取整内存的大小到 48 字节,所以新切片的容量为 48 / 8 = 6

切片拷贝
copy(dest, src)

在大切片上执行拷贝操作时一定要注意对性能的影响。

上一篇 下一篇

猜你喜欢

热点阅读