go切片性能及陷阱

go切片性能及陷阱

数组

go语言中,切片是数组之上的抽象数据类型,而数组类型定义了长度和元素类型,且数组的长度和元素类型不可变。
数组初始化: arr := [3]{1,2,3}
注意,数组数量属于值类型,当数组被当做参数变量进行赋值或传递时,实际上会复制整个数组。因此,为了避免数组赋值,一般传递数组的指针。

切片

切片比数组更具灵活性,不需要指定长度。
切片初始化:langs := []string{"Go", "Python", "C"}make([]T, len, cap)
注意,切片可以扩容,且切片操作并不复制切片指向的元素,创建一个新的切片会复用原来切片的底层数组,因此切片操作是非常高效的。

切片的性能陷阱
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
}

func printMem(t *testing.T) {
    t.Helper()
    var rtm runtime.MemStats
    runtime.ReadMemStats(&rtm)
    t.Logf("%.2f MB", float64(rtm.Alloc)/1024./1024.)
}

func testLastChars(t *testing.T, f func([]int) []int) {
    t.Helper()
    ans := make([][]int, 0)
    for k := 0; k < 100; k++ {
        origin := generateWithCap(128 * 1024) // 1M
        ans = append(ans, f(origin))
        runtime.GC()
    }
    printMem(t)
    fmt.Println(len(ans))
}

func TestLastCharsBySlice(t *testing.T) { testLastChars(t, lastNumsBySlice) }
func TestLastCharsByCopy(t *testing.T)  { testLastChars(t, lastNumsByCopy) }

# go test -run=^TestLastChars  -v
    === RUN   TestLastCharsBySlice
        slice_test.go:43: 100.27 MB
    100
    --- PASS: TestLastCharsBySlice (0.28s)
    === RUN   TestLastCharsByCopy
        slice_test.go:44: 0.28 MB
    100
    --- PASS: TestLastCharsByCopy (0.25s)
    PASS

  • 可以看到 lastNumsBySlice 直接引用切片,底层数组在 printMem() 前并不会释放内存
  • lastNumsByCopy 使用复制方式,底层数组会被释放内存
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容