go1.14实现高性能内存分配器 – 峰云就她了
source link: http://xiaorui.cc/archives/6613?
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
go1.14实现高性能内存分配器 – 峰云就她了
go1.14版本中也更新了内存分配器。go先前的版本,在多GOMAXPROCS高频申请内存场景下会引起mheap.lock的锁竞争问题,所以在新版内存分配器着重解决这个问题。
go1.14内存分配器优化的逻辑简单说就是删除自由内存范围的概念,并使用位图跟踪自由内存,另外允许p缓存一部分bitmap。
该文章原文地址 http://xiaorui.cc/archives/6613
为什么mheap成为瓶颈?
虽然在go的内存设计中有多级缓存的概念 ( mcache、mcentral、mheap ),mcache由于绑定在P上,所以无锁的。central数组按照size class芬超了67个,每个mcentral都有一个锁,锁粒度在size class。但mheap结构是全局唯一,相关的内存分配及释放会独占mheap.lock。
go1.14内存分配器优化的逻辑简单说就是删除自由内存范围的概念,并使用位图跟踪自由内存,另外在p缓存一部分bitmap。
(有空再写) …
go官方给出的内存分配器设计方案,go proposal,https://github.com/golang/proposal/blob/master/design/35112-scaling-the-page-allocator.md
测试脚本,逻辑就是开协程不断的申请对象。
// xiaorui.cc
package main
import (
"fmt"
"sync"
"time"
)
type node struct {
ident string
context string
}
func run() {
iter := 100000
data := make(map[int]node, iter)
ts := time.Now().String()
for i := 0; i < iter; i++ {
data[i] = node{
ident: ts,
context: ts + ts + ts,
}
}
for i := 0; i < iter; i++ {
delete(data, i)
}
}
func batchRun() {
wg := sync.WaitGroup{}
for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
run()
wg.Done()
}()
}
wg.Wait()
}
func main() {
start := time.Now()
for i := 0; i < 100; i++ {
batchRun()
}
cost := time.Since(start)
fmt.Printf("time cost: %+v \n", cost)
}
在并发密集申请内存下,go1.14的内存分配性能是快了一些。(节字大小影响结果)
// xiaorui.cc
go 1.13 vs go 1.14
time cost: 1m11.458039901s
time cost: 57.242940201s
go 1.13 vs go 1.14
time cost: 2m27.298913751s
time cost: 1m56.458370589s
cpu消耗相差不大
通过golang pprof top对比,go 1.14的runtime.futex调用少于go1.13。使用strace统计也是同样的结果。
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK