Goにはガベージコレクションがあるのでプログラマがメモリ管理を意識することは少ない。とはいえ無駄にメモリを割り当てまくるとそれだけメモリアロケータとガベージコレクタが走る回数が増えてプログラムが遅くなってしまう。効率の良いプログラムを書こうと思ったらある程度はどういうふうに値がメモリ上に確保されるのか意識することが必要だ。
メモリシステムへの負荷を下げるにはメモリの量だけではなく回数を減らすことが有効である。Goでは構造体のレイアウトは自分で制御できるし、interior pointer(オブジェクトの内部を指しているポインタ)を取得することもできるので、必要な値をまとめてメモリ上に確保することができる。具体的には次のように行う。
type encoder {
buf []byte
scratch [80]byte
// その他のフィールド ...
}
func newEncoder() *encoder {
e := new(encoder)
e.buf = scratch[:]
return e
}
encoderという型がbufというフィールドを持っているのだけど、encoderは同時にscratchという80バイトのバッファのフィールドも持っている。new(encoder)は一発でスクラッチバッファを含むencoder全体をアロケートする。bufがだいたい常に80バイト以内に収まるのであれば、それ以上メモリを割り当てる必要はないから、アロケーションは1回だけで済む。encoderにscratchフィールドがなくて、別のnewの呼び出しでbufにメモリを割り当てていたとしたら、newの呼び出しは常に2回になるから、1回で済むのはずいぶんな節約だ。
アロケーションを少なくするというアイデアはいろいろなところで有効である。たとえば結果のスライスの長さをあらかじめ計算することができるなら、結果の長さがどうなるかをまず計算してからきっちり同じキャパシティを持ったスライスを割り当てて、そこに結果をappendしていくほうが、長さ0のスライスにappendしていくよりずっとよい。