Go:一个8bytes的内存优化

共 2765字,需浏览 6分钟

 ·

2021-08-24 21:16

最近看Dave Cheney 的一篇文章[1],发现一个有趣的代码片段,里面提到了一个 8byte 的内存优化。

代码片段是这样的:

func BenchmarkSortStrings(b *testing.B) {
 s := []string{"heart""lungs""brain""kidneys""pancreas"}
 b.ReportAllocs()
 for i := 0; i < b.N; i++ {
  var ss sort.StringSlice = s
  var si sort.Interface = ss
  sort.Sort(si)
 }
}

代码很简单,是对一个[]string做排序的内存分配压测

其中

var ss sort.StringSlice = s
var si sort.Interface = ss
sort.Sort(si)

等同于代码

sort.Strings(s)

涉及了对 []string 转换为实现排序的接口 sort.Interface

了解iface实现的同学知道其data会存储底层数据,一般是一个机器字长的大小(8bytes

slice24bytes: 底层数组指针(8bytes)+ 长度(8bytes)+ 容量(8bytes

直接存不下,就只能indirection, 存指向切片的指针了

创建前片指针的过程中,切片 escape 到了 heap 上,因为不知道原切片ss是否会在si使用过程中消失。

即,内存分配发生在了这里!

看下压测结果(go1.16):

go test sort_test.go -bench . -benchmem
goos: darwin
goarch: amd64
cpu: Intel(R) Core(TM) i5-5257U CPU @ 2.70GHz
BenchmarkInts-4         18846020                90.09 ns/op           24 B/op          1 allocs/op
PASS
ok      command-line-arguments  2.663s

结果就是24bytes啊,那所谓的8bytes优化在哪里呢

是相对于的go1.16前版本的go的, 比如go1.15下:

$ go1.15 test sort_test.go -bench . -benchmem
goos: darwin
goarch: amd64
BenchmarkSortStrings-4           8617881               172 ns/op              32 B/op          1 allocs/op
PASS
ok      command-line-arguments  1.649s

找了下具体提交,其实就是在内存分配里针对三个机器字大小增加了24bytessizeClass,避免原来的向上取整到32bytes

感兴趣的同学可以去看看具体实现:runtime: add 24 byte allocation size class[2]

题外话,好久没有更新了,不好意思了都,后边再捡起来 😂

参考资料

[1]

Dave Cheney的一篇文章: https://dave.cheney.net/2021/01/05/a-few-bytes-here-a-few-there-pretty-soon-youre-talking-real-memor

[2]

runtime: add 24 byte allocation size class: https://github.com/golang/go/commit/14c7caae5074fdf0d97a3ad995e20c63e4065cbf



推荐阅读


福利

我为大家整理了一份从入门到进阶的Go学习资料礼包,包含学习建议:入门看什么,进阶看什么。关注公众号 「polarisxu」,回复 ebook 获取;还可以回复「进群」,和数万 Gopher 交流学习。

浏览 32
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报