我在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)
}
我在Core-i7 2600上运行此版本,版本为1.6 64位(32位也是相同的结果)和16 GB RAM(在WINDOWS 10上) 因此当alloc为65536(正好是64K)时,它运行30秒(!!!!)。 当alloc为65535时,需要大约200ms。 有人可以向我解释一下吗? 我在家里用我的核心i7-920 @ 3.8GHZ尝试了相同的代码,但它没有显示相同的结果(两者都花了大约200ms)。任何人都知道发生了什么?
答案 0 :(得分:5)
设置GOGC =关闭改进的性能(低至100ms)。为什么?
因为escape analysis。使用go build -gcflags -m
构建时,编译器会打印任何分配到堆的分配。它真的取决于你的机器和GO编译器版本,但是当编译器决定分配应该移动到堆时,它意味着两件事:
1.分配将花费更长时间(因为&#34;在堆栈上分配&#34;只是1 cpu指令)
2. GC将不得不在以后清理该内存 - 耗费更多的CPU时间
对于我的机器,65536字节的分配转储到堆,65535不转移。
这就是为什么1个字节将整个过程从200ms改为30s的原因。惊人..
答案 1 :(得分:0)
原因很简单。
const alloc int = 65535
0x0000 00000 (example.go:8) TEXT "".main(SB), ABIInternal, $65784-0
const alloc int = 65536
0x0000 00000 (example.go:8) TEXT "".main(SB), ABIInternal, $248-0
区别在于创建切片的位置。