sync.Poolのドキュメントの無料
改定ガベージコレクタ(以降GC)は、ガベージを常に収集するのではなく、一定の間隔で収集します。 コードが一部のデータ構造にメモリを割り当ててから、それらを解放する場合(円内など)、これにより、新しいメモリを割り当てるために
runtime
をOSに強制するなど、GCに負荷がかかります。 想像してみてください:
ピース (たとえば
[]byte
)を選択し、それを操作し、リリースします。 GCが「スリープから復帰」してこの
ピースを収集するまでに時間がかかります。 この時点で同じ
ピースをもう1つ割り当て、OSに十分なメモリが既に割り当てられていない場合、アプリケーションはOSにさらにメモリを要求するように強制されます。 アプリケーションの時間に応じて、OSからのメモリ要求は永遠に続きます。 そして、まさにこの時点で、どこかほこりっぽい、その古い「うまくいった」
作品の時間を待っています。
どうする?
- プールを作成する
- ピースの状態をリセットする
- 使用済みのピースをプールに入れる
- プールから新しいピースを取ります
プールを作成
import( "sync" ) var bytesPool = sync.Pool{ New: func() interface{} { return []byte{} }, }
状態をリセット
プールに入れる
const maxCap = 1024 if cap(ary) <= maxCap {
プールから取る
nextAry := bytesPool.Get().([]byte)
Newに関する説明
New
関数は、空の
[]byte{}
作成し、これらの変換も
interface{}
、またはその逆も行います。
[]byte
場合、
append
を使用してビルドする可能性が最も高いため、基本的にこのアプローチは採算が取れません。
プール全体を扱う2つの関数を作成する方がはるかに便利です。
覚えている
sync.Pool
万能薬でsync.Pool
ません- goroutinoセーフプール
- プールは、GCの最初の起動時に必ずしもデータを解放するわけではありませんが、いつでも解放できます
- プールサイズを決定および設定する方法はありません
- プールのオーバーフローを処理する必要はありません
- どこにいてもプールをプールする必要はまったくありません。それは、パッケージ内だけでなく他のパッケージでも、複数の共有オブジェクトが共有されたときにショックアブソーバーとして作成されました
- おそらく、GCを支援する必要性/機会が明白になる状況があるか、またはそうなるでしょう
- バッファチャネルを使用して、サイズが制限されたプールが作成されます
プールを使用する良い例は、
fmtパッケージです。
109行
目から150行目まで。