| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> Java知识库 -> go语言内存对齐 -> 正文阅读 |
|
[Java知识库]go语言内存对齐 |
?大家好,我是peachesTao,今天跟大家聊一聊go语言中的内存对齐,这个知识点涉及到计算机运行原理,也是go面试中经常被问的问题 通过这篇文章你可以了解到go语言中内存是怎么对齐的,以及代码怎么写才能更有效的利用内存。 本次分享分为4个部分
什么是内存对齐?以下定义来源于网络
为什么要内存对齐?CPU把内存看成一块一块的,一块内存可以是2、4、8、16个字节,CPU访问内存也是一块一块的访问,cpu一次访问一块内存的大小我们定义为粒度, 32位CPU访问粒度是4个字节,64位CPU访问粒度是8个字节。 内存对齐是为了减少访问内存的次数,提高CPU读取内存数据的效率,如果内存不对齐,访问相同的数据需要更多的访问内存次数。 我们用一个int32类型的变量a
分别以内存不对齐和内存对齐来说明两者之间的差异,此处以32位CPU为基准
假设有一段地址0xc000000000-0xc000000007,0xc000000000中已经存放数据,不对齐时变量a中的4个字节的数据被一个接一个的放在0xc000000000的后面地址空间0xc000000001-0xc000000004中。 访问a时CPU按照访问粒度4个字节从内存读取,当发现第一个地址0xc000000001不在对齐边界上,它属于0xc000000000-0xc000000003这个粒度块中,于是就从当前块的对齐边界地址0xc000000000处开始读取4个字节,即0xc000000000-0xc000000004。 由于这次读取只读到了我们要的0xc000000001-0xc000000003地址空间的三个字节数据,还有一个字节数据没有读到,于是CPU又对内存进行第二次读取,读到了0xc0000000041-0xc000000007空间的4个字节数据。 然后CPU将第一次读到的0xc000000000和第二次读到的0xc000000005-0xc000000007空间上的数据删除,最后在寄存器中将剩余的数据合并,得到了我们最终想要的数据0xc000000001-0xc000000004,见下图
对齐时地址0xc000000000后面的三个字节的空间会被填充(为什么会被填充?这是对齐规则决定的,后面会详细解释),变量a中的4个字节的数据被存放在0xc000000004-0xc000000007空间中。 取出时CPU按照访问粒度4个字节进行读取,当发现第一个地址0xc000000004在对齐边界上,于是直接读取0xc000000004-0xc000000007空间中4个字节数据。 我们看到当内存对齐时只读一次内存就能拿到的变量a的数据,见下图 如何做才能内存对齐在前面的例子中我们看到当内存不对齐时会填充,其实这部分工作是由编译器完成的,程序员并不需要关心,但作为一名合格的码农来说,我们还是有必要知道编译器内存对齐的原理。 这部分分三个点来讲
编译器对齐系数 对于常见的CPU
另外要注意,不同硬件平台占用的大小和对齐值都可能是不一样的。因此本文的值不是唯一的,用的时候需按实际情况考虑 在C语言中可以通过预编译指令
数据类型的大小和对齐系数 在unsafe包中有三个函数
unsafe.Sizeof 返回变量x的占用字节数,但不包含它所指向内容的大小,对于一个string类型的变量它的大小是16字节,一个指针类型的变量大小是8字节(基于64位机器,下文中的例子也是,不再说明) unsafe.Offsetof 返回结构体成员地址相对于结构体首地址相差的字节数,称为偏移量,注意:x必须是结构体成员 unsafe.Alignof?返迴变量x需要的对齐倍数,它可以被x地址整除 这三个方法只有方法的声明,实现是在编译期间执行的,编译期间源码在 注意:以上三个函数计算结果跟硬件平台、编译器实现有关,具体值以实际情况 为准 下面列出常见数据类型的大小和对齐值
它们的大小和对齐系数如下
编译器内存对齐规则 考虑到结构体方便举例,这里只介绍结构体的对齐规则,其实其他的所有类型都需要做内存对齐
我们用一个实例解释一下
先看结果
demo1占用32个字节大小,分析如下: 首先根据第一条规则:
第一条规则算下来结构体占用大小=8+16+2=26 接下来看第二条规则 通过上面分析结构体最大成员变量大小为16,编译器默认对齐系数为8,取两者最小值8的最小整数倍,因本身结构体当前大小为26,所以最后结构体大小=4*8=32 如果我们把成员a和b的位置调换一下情况会怎样?
结果如下
占用24个字节空间,为什么少了8个字节大小?接着分析: 首先根据第一条规则:
第一条规则算下来结构体占用大小=16+2+2=20 接下来看第二条规则 通过上面分析结构体最大成员变量大小为16,编译器默认对齐系数为8,取两者最小值16的最小整数倍,因本身结构体当前大小为20,所以最后结构体大小=3*8=24 通过demo1和demo2分析对比,结构体成员变量的顺序会影响整个结构体的占用内存大小 对于内存对齐,程序员能做点什么编译器已经对变量做了内存对齐,程序员可以通过调整成员变量顺序减少结构体占用大小,节省内存,对性能要求很高的场景还是有必要做的,如果对性能要求不那么高,记住一个大原则:将大的变量放在前面,如果你完全不care性能,则可以略过此篇文章。 有人可能会问,编译器能把内存对齐的工作做了,为什么不接着在编译期把结构体成员变量顺序优化呢?这样可以降低程序员的心智负担。 如果编译器自动优化了结构体成员变量顺序,数据经过网络传输后怎么能正确的还原回原来的结构体呢? reference https://zhuanlan.zhihu.com/p/53413177 https://ms2008.github.io/2019/08/01/golang-memory-alignment/ https://blog.csdn.net/EDDYCJY/article/details/119769942 https://www.xhyonline.com/?p=1238 https://blog.csdn.net/weixin_33769207/article/details/91699678) https://stackoverflow.com/questions/381244/purpose-of-memory-alignment https://developer.ibm.com/articles/pa-dalign/ https://github.com/golang/go/wiki/cgo#struct-alignment-issues: https://www.cnblogs.com/qcrao-2018/p/10964692.html |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/23 13:20:10- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |