Golang切片附加和重新分配

时间:2017-11-03 00:44:36

标签: go slice goroutine

我最近一直在学习,并在重新分配时遇到有关切片行为的问题。假设我有一段指向结构的指针,例如:

var a []*A

如果我将这个切片传递给另一个函数,我的理解是内部按值传递切片头,它在一个单独的goroutine上运行,只是从切片读取,而启动goroutine的函数继续附加到切片,是一个问题?例如:

package main

type A struct {
    foo int
}

func main() {
  a := make([]*A, 0, 100)
  ch := make(chan int)
  for i := 0; i < 100; i++ {
    a = append(a, &A{i})
  }
  go read_slice(a, ch)
  for i := 0; i < 100; i++ {
    a = append(a, &A{i+100})
  }
  <-ch
}

func read_slice(a []*A, ch chan int) {
   for i := range a {
     fmt.Printf("%d   ", a[i].foo)
   }
   ch <- 1
}

因此,根据我的理解,当read_slice()函数在其自己的goroutine上运行并带有slice头的副本时,它有一个指向当前后备数组的底层指针,以及调用它时的大小可以访问foo的。

但是,当另一个goroutine附加到切片时,它会在超出容量时触发重新分配。 go运行时是不是将内存释放到read_slice()中使用的旧后备数组,因为在该函数中有对它的引用?

我尝试用&#34;运行-race slice.go&#34;但那并没有报告任何事情,但我觉得我可能在这里做错了什么?任何指针都会受到赞赏。

谢谢!

1 个答案:

答案 0 :(得分:3)

在没有对后备阵列的引用之前,GC不会收集后备阵列。该计划没有比赛。

考虑没有goroutines的场景:

  a := make([]*A, 0, 100)
  for i := 0; i < 100; i++ {
    a = append(a, &A{i})
  }
  b := a
  for i := 0; i < 100; i++ {
    b = append(b, &A{i+100})
  }

当附加到a分配新的后备阵列时,切片b将继续引用带有前100个指针的后备数组。切片a没有留下对后备数组的悬空引用。

现在将goroutine添加到场景中:

  a := make([]*A, 0, 100)
  for i := 0; i < 100; i++ {
    a = append(a, &A{i})
  }
  b := a
  go read_slice(a, ch)
  for i := 0; i < 100; i++ {
    b = append(b, &A{i+100})
  }

goroutine可以愉快地使用切片a。没有悬空参考。

现在考虑问题中的程序。它的功能与此处的最后一个片段完全相同。