多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
[TOC] > [参考](https://github.com/geektutu/high-performance-go/blob/master/charpter-2/hpg-slice.md) ## 数组 - 数组是值传递,与C的数组不同,C中指针传递,指向第一个元素 - Go 中为了避免复制数组,一般会传递指向数组的指针 ``` func square(arr *[3]int) { for i, num := range *arr { (*arr)[i] = num * num } } func TestArrayPointer(t *testing.T) { a := [...]int{1, 2, 3} square(&a) fmt.Println(a) // [1 4 9] if a[1] != 4 && a[2] != 9 { t.Fatal("failed") } } ``` ## 切片 - 切片操作并不复制切片指向的元素,创建一个新的切片会复用原来切片的底层数组,因此切片操作是非常高效的 - 切片本质是一个数组片段的描述,包括了数组的指针,这个片段的长度和容量(不改变内存分配情况下的最大长度) ``` struct { ptr *[]T len int cap int } ``` ![](https://geektutu.com/post/hpg-slice/slice.jpg) ``` nums := make([]int, 0, 8) nums = append(nums, 1, 2, 3, 4, 5) nums2 := nums[2:4] printLenCap(nums) // len: 5, cap: 8 [1 2 3 4 5] printLenCap(nums2) // len: 2, cap: 6 [3 4] nums2 = append(nums2, 50, 60) printLenCap(nums) // len: 5, cap: 8 [1 2 3 4 50] printLenCap(nums2) // len: 4, cap: 6 [3 4 50 60] ``` ## 性能陷阱 ### 大量内存得不到释放 ``` func lastNumsBySlice(origin []int) []int { return origin[len(origin)-2:] } func lastNumsByCopy(origin []int) []int { result := make([]int, 2) copy(result, origin[len(origin)-2:]) return result } ``` ``` slice_test1.go 100.14 MB slice_test2.go 3.14 MB ``` 1. 申请的 100 个 1 MB 大小的内存没有被回收。因为切片虽然只使用了最后 2 个元素,但是因为与原来 1M 的切片引用了相同的底层数组,底层数组得不到释放,因此,最终 100 MB 的内存始终得不到释放 2. 而`lastNumsByCopy`仅消耗了 3.14 MB 的内存。这是因为,通过`copy`,指向了一个新的底层数组,当 origin 不再被引用后,内存会被垃圾回收(garbage collector, GC)