I stumbled upon an interesting thing while checking performance of memory allocation in GO.
package main
import (
"fmt"
"time"
)
func main(){
const alloc int = 65536
now := time.Now()
loop := 50000
for i := 0; i<loop;i++{
sl := make([]byte, alloc)
i += len(sl) * 0
}
elpased := time.Since(now)
fmt.Printf("took %s to allocate %d bytes %d times", elpased, alloc, loop)
}
I am running this on a Core-i7 2600 with go version 1.6 64bit (also same results on 32bit) and 16GB of RAM (on WINDOWS 10) so when alloc is 65536 (exactly 64K) it runs for 30 seconds (!!!!). When alloc is 65535 it takes ~200ms. Can someone explain this to me please? I tried the same code at home with my core i7-920 @ 3.8GHZ but it didn't show same results (both took around 200ms). Anyone has an idea what's going on?
Setting GOGC=off improved performance (down to less than 100ms). Why? becaue of escape analysis. When you build with go build -gcflags -m
the compiler prints whatever allocations escapes to heap. It really depends on your machine and GO compiler version but when the compiler decides that the allocation should move to heap it means 2 things: 1. the allocation will take longer (since "allocating" on the stack is just 1 cpu instruction) 2. the GC will have to clean up that memory later - costing more CPU time for my machine, the allocation of 65536 bytes escapes to heap and 65535 doesn't. that's why 1 bytes changed the whole proccess from 200ms to 30s. Amazing..