2017-11-03 9 views
0

私は最近勉強していましたが、再配置が発生したときのスライスの動作について質問がありました。私のような構造体へのポインタ、のスライスを持っていると想定します。私は別の関数に、このスライスを渡すようにした、と私の理解は、内部的に、これは上で動作する値によって、スライスヘッダを渡すということであればゴランスライスの追加と再割り当て

var a []*A 

Goroutineを起動した関数がスライスに追加され続けている間に、スライスから読み取るだけの問題ですか?たとえば:read_slice()関数は、スライスヘッダのコピーを持つ独自のゴルーチン上で実行されているよう

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 
} 

だから、私の理解から、それは現在の補助配列との大きさに根本的なポインタを持っていますそれが呼び出されたとき、私はfooにアクセスすることができます。

しかし、他のゴルーチンがスライスに追加しているときは、容量を超えたときに再割り当てがトリガーされます。実行時ランタイムは、その関数に参照があるので、read_slice()で使用されている古いバッキング配列にメモリを割り当て解除しませんか?

"go run -race slice.go"でこれを実行しようとしましたが、何も報告されませんでしたが、ここで何か間違っているように感じられますか?任意のポインタが評価されるだろう。

ありがとうございます!

答えて

3

バッキングアレイへの参照がなくなるまで、GCはバッキングアレイを収集しません。プログラムにはレースはありません。

なしゴルーチンとのシナリオを検討してください。

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}) 
    } 

bへの追加時にスライスaは最初の100個のポインタを持つバッキング配列を参照していきますが、新たな補助配列を割り当てます。スライスaには、バッキングアレイの参照が残っていません。

今のシナリオにゴルーチンを追加します。

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}) 
    } 

ゴルーチンは喜んでスライスaを使用することができます。ダングリングリファレンスはありません。

今質問のプログラムを考えてみましょう。最後のスニペットと機能的に同じです。

+0

お返事ありがとうございます! – muddy

関連する問題