KDOC 415: io.Readerのシグネチャはヒープエスケープを避けられる設計になっている
この文書のステータス
- 作成
- 2025-07-01 貴島
- レビュー
- 2025-07-19 貴島
概要
io.Reader, io.Writerのインターフェース設計には、ヒープのエスケープも関係しているという。
type Reader interface {
Read(p []byte) (n int, err error)
}
[]byte の初期化は呼び出し側の責務になっている。これによって呼び出し側がメモリ管理できるようになる。呼び出し側のスタックに留まり、ヒープにエスケープするのを抑えられる。Readを何度呼んでも新しいヒープ確保が発生しない。呼び出し側がヒープにする自由度もある。
実際に試してみる。
tmpfile=$(mktemp /tmp/tmpgo.XXXXXX.go)
cat > $tmpfile <<EOF
package main
func main() {}
// Read側で初期化して返すと、ヒープにエスケープしなければならない
func Read1() []byte {
return make([]byte, 1)
}
// 呼び出し側で初期化してもらうようにすると、ヒープにエスケープする必要がない
func Read2([]byte) {}
EOF
go build -gcflags="-m" -o bin $tmpfile 2>&1
rm bin
rm $tmpfile
/tmp/tmpgo.s6wAwW.go:3:6: can inline main
/tmp/tmpgo.s6wAwW.go:6:6: can inline Read1
/tmp/tmpgo.s6wAwW.go:11:6: can inline Read2
/tmp/tmpgo.s6wAwW.go:7:14: make([]byte, 1) escapes to heap
関連
抽象。
- 領域の確保を呼び出し側に任せると、呼ばれる側の都合で確保が増えるのを避けられる
関連。
- 参照: Stack or Heap? Going Deeper with Escape Analysis in Go for Better Performance。調べている中でio.Readerとio.Writerインターフェースの設計について言及していたのを見つけた
- 動機: KDOC 414: インターフェースがヒープにエスケープされるのを見る。調べるきっかけになった
- 前提: KDOC 225: mallocをアセンブラで見る。ヒープ確保がどういうものかの前提