四谈内存对齐

最近在思考改进项目中一模块的实现,该模块维护起来让我很是头疼,所有才有了整体换掉它的想法。设计和实现中利用了内存对齐的技术。关于内存对齐,我曾经写过三篇文章,第一篇介绍了计算内存对齐的方法和例子,第二篇说了一个内存对齐的应用;三谈内存对齐时,则从其本质上做了阐述,而这次实际上是继续在其本质上的做文章,结合本质谈谈为什么内存对齐的计算方法就应该是第一篇中所讲的那两条。

如果对内存对齐本质还不清楚的话,就看看我的内存对齐系列的第三篇吧。如果你清楚了本质,那么我们结合第一篇中交待的内存对齐计算方法来进一步探究,为什么计算的方法就是这个样子的。

再理解一下对齐系数/模数,众所周知Alignment module反映了CPU 取数据时对数据起始地址的限制-这个地址值必须能被Alignment module所整除,但继续仔细考虑下去,你会想到CPU在下一次取数据依然要从下一个能被Alignment module所整除的地址的地方去取,这显而易见,又能说明什么呢?如果说CPU第一次取数据的地址是first_read_address,那么连续下一次的地址就应该是first_read_address + Alignment module了,也就是说每次取数据的量就是Alignment module这么多,这样通过Alignment module我们又可以知道一个量,那就是:在Alignement module限制下,CPU一次能取Alignment module个字节;在“Data alignment: Straighten up and fly right”一文中作者也称之为"memory access granularity"。从应用层开发人员的角度理解:被访问变量的长度,就是CPU要去读取的字节数;而对齐系数又是限制CPU读取字节数的一个指标,有了这两个理解,解决下面的疑问就有了基础了。

在'也谈内存对齐'一篇中介绍了内存对齐的计算方法,这里不妨再引用一下:
1、数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。
2、结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。

疑问:对于数据成员对齐规则:为什么每个成员的对齐都要按照Min(指定对齐模数,数据成员自身长度)来确定呢?为了不用Max(指定对齐模数,数据成员自身长度)呢,用Max值对齐的不更加完美么?同样对于结构的整体对齐规则也一样有此疑问。这里我们还是举个例子更加直观:
#pragma pack(8)
struct Foo {
    char    a;
    int    b;
    short    c;
};
#pragma pack()
我们先来看数据成员对齐,以b为例子,按照规则的说法,sizeof(b) = 4 < 8,那么Address_of_b = Start_Address_of_Foo + 4; 我们来看看当应用的代码里访问b的时候,CPU做了些什么?Address_of_b一半情况下是不能被8整除的,在不能被8整除的情况下,我们去访问b,这里我要提两个问题:
1) 访问b的时候是否会因内存没有对齐到8上而触发core呢?(在Sun SPARC上因访问未对齐地址上的变量时会出core)
2) 为什么不将b放到Start_Address_of_Foo + 8这个地址上呢?

下面一一说说我的理解:
根据前面所说,程序在访问b的时候,CPU实际不一定是从Address_of_b这个地址上开始读取的。如果b这个地址恰巧既能被4整除,也能被8整除(如地址24),那就无可厚非了。但是如果这个地址只能被4整除,而不能被8整除(如地址12),那么此时CPU读取的地址肯定是从Address_of_b – 4开始读取8个字节的,也就是说实际上CPU都是从能被8整除的地址上读取的,而且一次读了8个字节,b所在的位置恰是这个8个字节中的后4个字节,所以不存在触发core的可能。

第二个问题,sizeof(b) = 4 < 8,为什么就要按照4而不是按照8去安排b的地址呢?我们不妨按照8去给b分配地址,Address_of_b' = Start_Address_of_Foo + 8,这样的话CPU也能一次将b读取,而且是从b的起始地址开始读,似乎更完美。但你看出问题了么?这么做浪费的空间显然大了很多。将b安排在Address_of_b'比安排在Address_of_b多浪费了一半空间。

同样整体对齐原则也是同样的道理。内存对齐计算显然有两个目标:一是减少CPU的访存次数;第二个就是还要保持存储空间的效率足够高。

被推荐为最具Bus气质的优秀Blogger首批参选者

下班回家,坐在沙发上抱着本本打开"Bus"的后台管理中心,发了一篇文章后,发现居然有5条短消息未读。遂打开查看。发现其中有一条题为"恭喜您被推荐为‘全球最具Bus气质的Blogger’"的消息,而且是"blogbus"发来的,看第一眼很兴奋,后一想是不是Bus在后台给每个bus用户群发的消息呢。再往上又看到一条"BlogBus六周年庆典开始啦!"的消息,里面恰好有一个"全球最具Bus气质的Blogger倾城评选"的链接,为了一探究竟我打开了这个链接,看到了评选首页以及下面的200个首批候选者,翻了几页,居然在里面真的看到了自己^_^。

按照短信息里的说明,我将投票标志图标放到了我博客主页的右侧边栏里了,其实我很清楚自己肯定评不上最具Bus气质的Blogger,但是能被bus推荐为候选之一,也是很兴奋的,毕竟自己坚持写blog的行为得到了肯定,这一点就足以让我满足了,呵呵。

如果你认可我博客的内容,那就多点一下鼠标,投上一票,haha^_^

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言精进之路1 Go语言精进之路2 Go语言编程指南
商务合作请联系bigwhite.cn AT aliyun.com

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats