Posted at

構造体のsliceはポインタ定義しない方がハイパフォーマンス


Goで構造体slice

Goの構造体sliceはいつもポインタで定義していましたが、

要素追加の時毎回allocationが走るので初期化時に構造体のsliceにした方がパフォーマンス的に良いそうです。

package main

import (
"strconv"
"testing"
)
type human struct {
age int
name string
}
func BenchmarkPointerSlice(b *testing.B) {
// 初期化時にslice分のメモリ容量を確保している
people := make([]*human, 0, b.N)
b.ResetTimer()
for i := 0; i < b.N; i++ {
people = append(people, &human{
age: i,
name: strconv.Itoa(i),
})
}
}
func BenchmarkSlice(b *testing.B) {
// ポインタ分の容量のみ確保している
people := make([]human, 0, b.N)
b.ResetTimer()
for i := 0; i < b.N; i++ {
// ここで毎回allocate
people = append(people, human{
age: i,
name: strconv.Itoa(i),
})
}
}

検証結果

~/.ghq/github.com/0daryo/playground  go test -bench . -benchmem

goos: darwin
goarch: amd64
pkg: github.com/0daryo/playground
BenchmarkPointerSlice-8 15123596 77.8 ns/op 39 B/op 1 allocs/op
BenchmarkSlice-8 46061704 28.7 ns/op 7 B/op 0 allocs/op
PASS
ok github.com/0daryo/playground 3.471s
go test -bench . -benchmem 4.58s user 0.91s system 148% cpu 3.693 total

確かに実体の配列の方が3倍くらい速くてメモリ効率も良い

構造体のコピーコスト < allocation回数のコストだということだと思うのですが、オブジェクトサイズがあまりにも大きい場合はまた別問題かもしれません。