はじめに
メモリ領域にはスタックとヒープがあります。
スタックは関数呼び出しやその中で使われるローカル変数などが格納されるメモリ領域。
ヒープは動的にメモリが割り当てられる領域で、サイズの決まっていないデータや関数外で参照されたりする場合に使用するメモリ領域。
ヒープが大量に使用されてしまうと処理動作が遅くなるため、パフォーマンス改善をしていく際にこれらの知識が必要そうだったので、サンプルコードで確認したいと思います。
コード
package main
// スタック上に割り当て
func stackExample() int {
x := 42
y := x + 1
return y
}
// ヒープ上に割り当て
func heapExample() *int {
z := 42
return &z
}
func main() {
_ = stackExample()
_ = heapExample()
}
動かしてみる
コンパイルする際に、-gcflags -mをつけると、エスケープ解析のログを出力することができます。
このエスケープ解析というもので変数をスタックからヒープに移動させるかどうかを判別しているようです。
go build -gcflags -m main.go
stackExampleのx,yはエスケープされていません。
heapExampleのzはポインタを返しており、関数外で参照される可能性があるためヒープに移動されています。
# command-line-arguments
./main.go:3:6: can inline stackExample
./main.go:9:6: can inline heapExample
./main.go:14:6: can inline main
./main.go:15:18: inlining call to stackExample
./main.go:17:17: inlining call to heapExample
./main.go:10:2: moved to heap: z