Смотрим стандартный логгер из пакета log. В его структуре находится поле(свойство) buf:
type Logger struct {
mu sync.Mutex // ensures atomic writes; protects the following fields
prefix string // prefix on each line to identify the logger (but see Lmsgprefix)
flag int // properties
out io.Writer // destination for output
buf []byte // for accumulating text to write
isDiscard int32 // atomic boolean: whether out == io.Discard
}
Функция log.New() также не инициализует это поле и оно остается nil, что видно под дебаггером.
Если запустить вот такой бенчмарк с -benchmem:
var stdLgr = log.New(bufWriter, "", log.Ldate)
func Benchmark_Stdlog(b *testing.B) {
for i := 0; i < b.N; i++ {
bufWriter.Reset()
stdLgr.Printf("any info message")
}
}
То получаем:
Benchmark_Stdlog-4 360367 2898 ns/op 16 B/op 1 allocs/op
, где наглядно видно что логгер делает только одну аллокацию и только для операции fmt.Sprintf() внутри себя. Хотя под дебагером видно что слайс buf наращивает свою длину согласно принятому в Go алгоритму: 8, 16,32,64 байта.
Это ошибка бенчмарка, что он не видит аллокаций для полей структур типа []byte (возможно и иных слайсов!) или это особенное поведение компилятора Go для неинициализированного слайса байт?
Кстати, если заменить поле логгера на глобальный буфер этого же типа:
var buf []byte
то бенчмарк точно также не видит аллоцирование памяти функцией append()!
Кто-то может объяснить что происходит?