本文主要是介绍白话内存对齐,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
内存对齐,这个词,相信大家并不陌生,往往听说对齐有多好多好。
那么到底是在对齐什么呢??为什么要对齐,不对齐不行吗?
接下来,带大家用最朴实无华的语言,来理解内存对齐。
请忽略,以下例子中的部分地址等不合理性,专注于故事本身。
一、CPU总线是一只手
以32位系统为例,对应的数据总线宽度是32位,其通过数据总线获取内存中的数据。
32bit / 8bit = 4byte
即,CPU一次性最多只能拿到4个字节数据。
那么假设CPU需要获取0x01地址上的一个字节,由于在内存中,每个地址对应一个字节,而CPU发起一次获取数据,总线宽度就是4字节,故只能从顶部与内存顶部对齐,开始每次寻址4个字节。
你可以想象CPU的总线就是,一只手,每次只能拿连续的4字节数据。如下图所示:
如果内存中的数据刚好,落在这只手的范围内,那么就很容易一次性取完数据。但是如果,数据跨越了一个手,如下图:
那么CPU就需要取2次,然后合并才能完成数据的获取,效率更低了。
内存对齐的目的,就是为了尽可能减少CPU取数据的次数,从而提高效率。
二、内存对齐就是内存地址对齐
在程序中,假设有个结构体,我们定义如下:
struct A
{int x; // 4Bchar b; // 1Bint y; // 4Bchar c; // 1B
};int main()
{A a;return 0;
}
A结构体,明显字节数超过4了,不可能一次取完,实际需要4次。
第一条:结构体变量a的地址必须可以被4整除,也就是4字节对齐。因为手的宽度是4字节,那么a地址刚好就是取数据时,手的开始位置。很幸运,一般的编译,不管你定义的变量,还是malloc的内存,都是4字节对齐了的。所以这条,心里清楚就行了。
第二条:结构体内部保持4字节对齐。如上所示按struct A内部定义,a实际大小为4B*4=16B,对不足4字节的char b和char c,编译器会自动填充到4字节长度。CPU这只抓手,需要抓4次,才能完成a变量的获取。此时,效率就很低了,所以我们需要对结构体内部进行调整,如下:
struct A
{int x; // 4Bint y; // 4Bchar b; // 1Bchar c; // 1B
};
调整后,这个结构体,占用4+4+4=12B,CPU3次就可以取完。提高了效率。
我们在编程时,所以需要按照字节对齐,来调整结构体、数组等的布局方式。
三、#pragma pack(4)
这是设置结构体内存对齐字节数,编译器会对不足的字节进行填充。
四、_aligned_malloc()和memalign()
这是申请一块内存,与malloc的区别是,这2函数申请的内存地址是指定字节数对齐的。
其他觉得不错的,内存对齐文章:
《不可不知的内存对齐(Memory Alignment)》
《什么是字节对齐,为什么需要字节对齐》
《#pragma pack()用法详解》
若对你有帮助,欢迎点赞、收藏、评论,你的支持就是我的最大动力!!!
同时,阿超为大家准备了丰富的学习资料,欢迎关注公众号“超哥学编程”,即可领取。
这篇关于白话内存对齐的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!