Go的类型变量在内存中布局中的一个奇怪问题。
研究Go的类型变量,在内存中的布局的时候,遇到了一个怪异的问题(备注:笔者机器是64位系统,这很重要)。
package main import "fmt" func main() { a1 := 1 a2 := 2 fmt.Printf("%p\n", &a1) fmt.Printf("%p\n", &a2) fmt.Println() b1 := "1" b2 := "2" fmt.Printf("%p\n", &b1) fmt.Printf("%p\n", &b2) fmt.Println() c1 := []int{1} c2 := []int{2} fmt.Printf("%p\n", &c1) fmt.Printf("%p\n", &c2) }
结果
0xc420070030 0xc420070038 0xc420070050 0xc420070060 0xc42007a000 0xc42007a020
根据结果,可以明显的看出,int类型占8个byte,string类型占16byte,所以,按照Go语言的设计(官方博客说明),slice应该占24byte才对,但是事实却是占用了32byte的空间。
翻了很多资料,最后在雨痕的Go源码分析第四章内存分配中找到了答案。
分配器将其管理的内存块分为两种:
- span: 由多个地址连续的页(page)组成的大块内存
- object: 将 span 按特定大小切分成多个小块,每个小块可存储一个对象
……
用于存储对象的 object,按 8 字节倍数分为 n 种。比如说,大小为 24 的 object 可用来存储 范围在 17 ~ 24 字节的对象。这种方式虽然会造成一些内存浪费,但分配器只需面对有限 的几种规格(size class)小块内存,优化了分配和复用管理策略。
因为slice需要24byte,根据Go的内存分配策略,分到32byte。
雨痕并没有在书中指出
8 字节倍数分为 n 种
代码实现在哪里。
我在这里补充下,在$GOROOT/src/runtime/msize.go的函数initSizes找到这个实现策略。
// Initialize the size_to_class tables. nextsize := 0 for sizeclass = 1; sizeclass < _NumSizeClasses; sizeclass++ { for ; nextsize < 1024 && nextsize <= int(class_to_size[sizeclass]); nextsize += 8 { size_to_class8[nextsize/8] = int8(sizeclass) } if nextsize >= 1024 { for ; nextsize <= int(class_to_size[sizeclass]); nextsize += 128 { size_to_class128[(nextsize-1024)/128] = int8(sizeclass) } } }
更多架构、PHP、GO相关踩坑实践技巧请关注我的公众号:PHP架构师
原文地址:https://my.oschina.net/u/222608/blog/801798
相关推荐
-
Xftp5软件使用详解 服务器
2019-10-8
-
Redis八连问,你心慌吗?一记定心丸奉上 服务器
2020-6-24
-
厉害了,Dubbo 正式毕业! 服务器
2019-5-25
-
码云 Gitee 通知系统更新啦! 服务器
2020-6-13
-
Linux系统进程CPU使用率限制脚本 服务器
2019-10-9
-
虚拟机网卡丢失解决方法 服务器
2019-9-18
-
发现大量的TIME_WAIT解决办法 服务器
2019-9-19
-
详解如何用源代码安装软件,以及如何卸载它 服务器
2019-3-3
-
Linux(CentOS 7)环境下安装MySQL 服务器
2019-9-15
-
linux-版本相关 服务器
2019-6-22