Goは、しばしばシンプルで高速と呼ばれる言語です。しかし、特にメモリの扱いに関しては、その背後で多くの魔法をかけます。データの保存場所と方法を理解することで、より効率的なコードを書き、不要な割り当てを回避し、プログラムの動作をよりよく理解することができます。
スタックとヒープ:基本
スタック — LIFO(last in, first out)の原則で動作するメモリ。変数は関数を終了するまで存続します。スタックの操作は高速で、ほとんど無料です。
ヒープ - 寿命を事前に決定できないオブジェクトのメモリ領域。ガベージコレクタ(GC)によって管理されます。割り当てはより高価であり、アセンブリはプログラムを遅くする可能性があります。
主な違い: スタックでは、関数を終了するとメモリが自動的に解放されますが、ヒープでは GC によって監視されます.
エスケープ分析:誰が一団に逃げましたか?
Goコンパイラは変数に遭遇すると、それをスタックまたはヒープのどこに格納するかを決定します。このプロセスは escape analysis.
変数が関数の外に「実行」されると、ヒープに送信されます。そうでない場合は、スタックに残ります。
例 1. ローカル変数(スタックに残る)
func sum(a, b int) int {
c := a + b
return c
}
例 2. 変数がヒープに移動する
func makePointer() *int {
x := 42
return &x
}
ここでは、xがポインタを返します。関数を終了するとスタックがクリアされ、値が失われます。したがって、xは、生き続けるためにヒープに「逃げます」。

エスケープ解析を確認する
go build -gcflags="-m" main.go
出力例:
./main.go:5:6: moved to heap: x
変数が束になって逃げるのはいつですか?
ポインタの関数から戻ります。
閉鎖状態で保存されます。
インターフェースに転送されます(時々)。
構造体のサイズが大きすぎてスタックに収まりません。
例3.閉鎖
func adder() func(int) int {
sum := 0
return func(x int) int {
sum += x
return sum
}
}
ここでは、sumは、adder関数よりも長く生きる必要があるため、ヒープに格納されます。
実際のスタックとヒープ
特性 | スタック | 山 |
|---|---|---|
寿命 | 機能が実行されている間 | GC組み立て前 |
アクセス速度 | 非常に速い | 遅く |
管理 | 自動 | ゴミ収集員 |
保存場所 | ローカル変数 | ポインタ、閉鎖、長寿命オブジェクト |
効率的なコードの書き方
不要なポインタは避けてください。 ポインターが多いほど、混乱する可能性が高くなります。
可能であれば、リンクではなく値を使用してください。
エスケープ分析に注意してください。 Goは、必要ないように見える場合でも、ヒープにメモリを割り当てることがあります。
山を恐れないでください。 最適化は重要ですが、早すぎる最適化は悪です。
合計
Goでデータがどこに保存されているかを理解することで、より効率的なコードを書くことができます。 Escape analysis — これは、各変数の運命を決定するツールです。そして、そのルールを知ることで、ヒープ内の余分な割り当てによる予期しないブレーキを回避できます。
B コディケ Goの完全なコースがあります。最も基本的なものから高度なトピックまで。構文、メモリの操作、競合性を分析し、知識を強化するのに役立つミニプロジェクトを作成します。
また、アクティブな テレグラムチャンネル、ここでは素晴らしいアイデアについて話し合い、経験を共有し、課題を一緒に分析します。学習は有益であるだけでなく、楽しいものになります。
