メモリ割り当ての削減:sync.PoolとArena
オブジェクトの再利用、sync.Pool、GC負荷の削減
「メモリ割り当ての削減:sync.PoolとArena」はCoddyKit上の無料Go Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはGo Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Go Academyコースには全4レッスンが含まれています。
割り当てを減らす理由
ヒープへの各割り当ては、最終的にGCの作業を発生させます。割り当てを減らすとGCの頻度と停止時間が低下し、高トラフィックのサービスでスループットとテールレイテンシが向上します。
まずプロファイリング
最適化する前に、必ずプロファイリングを行ってください。go test -benchmemと-alloc_spaceヒーププロファイルを使用して、実際に割り当てが集中している経路を特定します。直感だけを頼りに最適化しないでください。
sync.Pool
sync.Poolは、再利用可能なオブジェクトのスレッドセーフなプールです。頻繁に割り当てと破棄が行われる短命なオブジェクト(バイトバッファ、作業用マップ、リクエストコンテキスト)に使用します。
var pool = sync.Pool{
New: func() any { return &bytes.Buffer{} },
}
func process(data []byte) {
buf := pool.Get().(*bytes.Buffer)
buf.Reset()
buf.Write(data)
// use buf...
pool.Put(buf)
}Poolはキャッシュではありません
GCはいつでもプール内のアイテムをクリアできます。Poolは割り当ての負荷を減らすためのものであり、長期間保持するデータのキャッシュには使用しません。取得したオブジェクトは、どのgoroutineのものか分かりません。
再利用する前に必ずReset
使用する前に、プールされたオブジェクトをクリアしてください。以前の呼び出し元のデータが残っている可能性があります。bytes.Bufferの場合はReset()を呼び出し、スライスの場合は[:0]に再スライスします。
スライスの事前割り当て
最終的な長さが分かっている場合は、make([]T, 0, n)でスライスを事前に割り当てます。これにより、スライスの拡張に伴う繰り返しの倍増とコピーを避けられます。
results := make([]Result, 0, len(input)) // no reallocationsString builder
ループ内で中間的な文字列の割り当てが発生するのを避けるため、文字列の連結ではなくstrings.Builderを使用します。
var sb strings.Builder
for _, s := range parts { sb.WriteString(s) }
result := sb.String()bytes.Bufferのプール
bytes.Bufferは、プールで管理されることが特に多い型の1つです。JSONエンコード、HTTPレスポンスの構築、テンプレートのレンダリングで繰り返し発生する割り当てを避けるためにプールします。
Goのアリーナ(実験的)
Go 1.20以降には、実験的なアリーナパッケージ(golang.org/x/exp/arena)が含まれています。アリーナでは多数のオブジェクトを1つの大きなブロックに割り当て、そのブロックを一度に解放するため、オブジェクトごとのGCを回避できます。
値型
小さな構造体を値渡しすると、ヒープ割り当てを完全に避けられます。性能が重要なコードでは、小さな構造体へのポインタを使うパターンを避けてください。値を返すほうがコストが低い場合がよくあります。
影響の測定
前後で-benchmemを付けてベンチマークを実行し、benchstatで比較します。ns/opだけでなく、処理の主要経路におけるallocs/opの削減を目指してください。
BenchmarkProcess-8 1000000 125 ns/op 64 B/op 2 allocs/op
// After pooling:
BenchmarkProcess-8 1000000 48 ns/op 0 B/op 0 allocs/opクイックチェック
割り当てを減らす用途でsync.Poolを安全に使えるのは、どのような特徴があるためですか?
まとめ:割り当ての削減
重要なポイント:
- まずプロファイリングを行い、最適化前に-benchmemとヒープの-alloc_spaceを確認します
- 頻繁に割り当てと破棄が行われるオブジェクトにはsync.Poolを使用し、再利用前には必ずResetします
- make([]T, 0, n)でスライスを事前に割り当て、連結にはstrings.Builderを使用します
- 値型はヒープ割り当てを避けます。改善をベンチマークで検証してください
AI チューターと学ぶ Go — 無料
ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。
- コース
- 51
- レッスン
- 203
よくある質問
「メモリ割り当ての削減:sync.PoolとArena」レッスンは無料ですか?
はい。「メモリ割り当ての削減:sync.PoolとArena」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Go Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Go Academyコースには全4レッスンが含まれています。
「メモリ割り当ての削減:sync.PoolとArena」で何を学びますか?
オブジェクトの再利用、sync.Pool、GC負荷の削減 ブラウザで直接実行するハンズオンコードでGo Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Go Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのGo Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。
「メモリ割り当ての削減:sync.PoolとArena」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このGo Academyレッスンでコードを書いて実行できますか?
はい。すべてのGo Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- スタックとヒープ、エスケープ解析
- GoのメモリモデルとHappens-Before
- ガベージコレクターの内部
- メモリ割り当ての削減:sync.PoolとArena