go:noescape

goのソース読んでるとたまに見かける go:noescape についてメモ.

go:noescapeはGoコンパイラエスケープ解析へのヒント。

エスケープとは、関数内でメモリに割り当てられた値が関数が終了したあとも、呼び出し元の関数や別のスレッドから値が参照されること

Goのコンパイラは値をヒープよりもスタックに割り当てようとする。スタックに割り当てると関数を抜けるとメモリ領域が廃棄されるので、ヒープ領域の取得やGCの回収するコストがかからずヒープに割り当てられるよりコストが低い。

だが、スタックに割り当てられた値のポインタがエスケープして参照されると、ダングリングポインタ(dangling pointer)が発生するので、エスケープ解析によってエスケープされないことがわかる値だけをスタックに割り当てる。

しかし、コンパイラはGoで書かれていない関数はエスケープ解析ができない。そのような関数でも、引数として渡されたポインタがエスケープしないことをgo:noescapeディレクティブの指定によってコンパイラに教えることができる。

Goの標準ドキュメントによると:

https://golang.org/cmd/compile/

The //go:noescape directive specifies that the next declaration in the file, which must be a func without a body (meaning that it has an implementation not written in Go) does not allow any of the pointers passed as arguments to escape into the heap or into the values returned from the function. This information can be used during the compiler’s escape analysis of Go code calling the function.

(超訳)//go:noescapeディレクティブはファイル内で次の関数宣言(ボディーの無い関数(つまり実装がGoで書かれていない関数)でなければならない)の、引数として渡るポインタがヒープやその関数の返り値にエスケープされることを一切許可しないことを明示する。この情報はコンパイラがその関数の呼び出すGoコードのエスケープ解析を行う際に利用することができる。