3.8 構造体のメモリ割り当てを高速化する

構造体のインスタンスを大量に作ったり破棄したりする場合、一度作ったインスタンスをキープしておき、使いまわしたいと思うことがあるでしょう。Goは、このようなインスタンスをプールするためのライブラリを、標準ライブラリとして提供しています。sync.Poolを使うと、OSにメモリをリクエストする回数が減り、同一プロセス内での再利用性が高まります。Goのランタイム内部におけるメモリ確保やOSに対するメモリのリクエストは比較的重い処理なので、プールしたインスタンスをうまく使いまわすことでパフォーマンスが向上します。

Goのライブラリでは、メモリ割り当て回数の少なさをパフォーマンスの指標として掲げることがあります。zerolog 1 などメモリ割り当て回数が少なく、高速性をアピールしているライブラリは、内部でこのsync.Poolを使ってメモリ割り当て回数を抑制しています。

sync.Poolを使うときは、この構造体のインスタンスを作成します。このインスタンスのNewフィールドに、新しいインスタンスを返す関数を設定します。

import "sync"

// 巨大な構造体
type BigStruct struct {
	Member string
}

// Poolは初期化関数をNewフィールドに設定して作成する
var pool = &sync.Pool{
	New: func() interface{} {
		return &BigStruct{}
	},
}

1つのプールは1つの型のインスタンスのみを扱います。プール内にストックがあれば、それをそのまま返すだけのシンプルな動作であり、種類ごとに切り替えるといった仕組みはありません。また、使い終わったら ...