内存对齐 我会带着你远行 2021-06-11 15:10 464阅读 0赞 首先由一个程序引入话题://环境:vc6 + windows sp2 程序1: #include "stdafx.h" #include <iostream> using namespace std; struct st1 { char a ; int b ; short c ; }; struct st2 { short c ; char a ; int b ; }; int main() { cout<<"sizeof(st1) is "<<sizeof(st1)<<endl; cout<<"sizeof(st2) is "<<sizeof(st2)<<endl; system("pause"); return 0 ; } 程序的输出结果为: sizeof(st1) is 12 sizeof(st2) is 8 问题出来了,这两个一样的结构体,为什么sizeof的时候大小不一样呢? 本文的主要目的就是解释明白这一问题。 内存对齐,正是因为内存对齐的影响,导致结果不同。 对于大多数的程序员来说,内存对齐基本上是透明的,这是编译器该干的活,编译器为程序中的每个数据单元安排在合适的位置上,从而导致了相同的变量,不同声明顺序的结构体大小的不同。 那么编译器为什么要进行内存对齐呢?程序1中结构体按常理来理解sizeof(st1)和sizeof(st2)结果都应该是7,4(int) + 2(short) + 1(char) = 7 。经过内存对齐后,结构体的空间反而增大了。 **在解释内存对齐的作用前,先来看下内存对齐的规则:** <!--\[if !supportLists\]-->1、 <!--\[endif\]-->对于结构的各个成员,第一个成员位于偏移为0的位置,以后每个数据成员的偏移量必须是min(\#pragma pack()指定的数,这个数据成员的自身长度) 的倍数。 <!--\[if !supportLists\]-->2、 <!--\[endif\]-->在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照\#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。 \#pragma pack(n) 表示设置为n字节对齐。 VC6默认8字节对齐 **以程序1为例解释对齐的规则 :** St1 :char占一个字节,起始偏移为0 ,int 占4个字节,min(\#pragma pack()指定的数,这个数据成员的自身长度) = 4(VC6默认8字节对齐),所以int按4字节对齐,起始偏移必须为4的倍数,所以起始偏移为4,在char后编译器会添加3个字节的额外字节,不存放任意数据。short占2个字节,按2字节对齐,起始偏移为8,正好是2的倍数,无须添加额外字节。到此规则1的数据成员对齐结束,此时的内存状态为: oxxx|oooo|oo 0123 4567 89 (地址) **(x表示额外添加的字节)** 共占10个字节。还要继续进行结构本身的对齐,对齐将按照\#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行,st1结构中最大数据成员长度为int,占4字节,而默认的\#pragma pack 指定的值为8,所以结果本身按照4字节对齐,结构总大小必须为4的倍数,需添加2个额外字节使结构的总大小为12 。此时的内存状态为: oxxx|oooo|ooxx 0123 4567 89ab (地址) 到此内存对齐结束。St1占用了12个字节而非7个字节。 St2 的对齐方法和st1相同,读者可自己完成。 **内存对齐的主要作用是:** <!--\[if !supportLists\]-->1、 <!--\[endif\]-->平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。 <!--\[if !supportLists\]-->2、 <!--\[endif\]-->性能原因:经过内存对齐后,CPU的内存访问速度大大提升。具体原因稍后解释。 图一: ![howProgrammersSeeMemory.jpg][] 这是普通程序员心目中的内存印象,由一个个的字节组成,而CPU并不是这么看待的。 图二: ![howProcessorsSeeMemory.jpg][] CPU把内存当成是一块一块的,块的大小可以是2,4,8,16字节大小,因此CPU在读取内存时是一块一块进行读取的。块大小成为*memory access granularity(粒度)*本人把它翻译为“内存读取粒度” 。 假设CPU要读取一个int型4字节大小的数据到寄存器中,分两种情况讨论: <!--\[if !supportLists\]-->1、<!--\[endif\]-->数据从0字节开始 <!--\[if !supportLists\]-->2、<!--\[endif\]-->数据从1字节开始 再次假设内存读取粒度为4。 图三: ![quadByteAccess.jpg][] 当该数据是从0字节开始时,很CPU只需读取内存一次即可把这4字节的数据完全读取到寄存器中。 当该数据是从1字节开始时,问题变的有些复杂,此时该int型数据不是位于内存读取边界上,这就是一类内存未对齐的数据。 图四: ![unalignedAccess.jpg][] 此时CPU先访问一次内存,读取0—3字节的数据进寄存器,并再次读取4—5字节的数据进寄存器,接着把0字节和6,7,8字节的数据剔除,最后合并1,2,3,4字节的数据进寄存器。对一个内存未对齐的数据进行了这么多额外的操作,大大降低了CPU性能。 这还属于乐观情况了,上文提到内存对齐的作用之一为平台的移植原因,因为以上操作只有有部分CPU肯干,其他一部分CPU遇到未对齐边界就直接罢工了。 图片来自:[Data alignment: Straighten up and fly right][Data alignment_ Straighten up and fly right] 参考网站: [http://www.cppblog.com/snailcong/archive/2009/03/16/76705.html][http_www.cppblog.com_snailcong_archive_2009_03_16_76705.html] [http://hi.baidu.com/hintonic/blog/item/f6e5a92058d99e6e93580707.html][http_hi.baidu.com_hintonic_blog_item_f6e5a92058d99e6e93580707.html] [http://bbs.ednchina.com/BLOG\_ARTICLE\_82066.HTM][http_bbs.ednchina.com_BLOG_ARTICLE_82066.HTM] [howProgrammersSeeMemory.jpg]: /images/20210522/99b4ed05215347119ccbd3abfe724125.png [howProcessorsSeeMemory.jpg]: /images/20210522/2970b1418c714632b57ab92d1b01c26b.png [quadByteAccess.jpg]: /images/20210522/956eef8f213746bdb58d9ad0336ea8bc.png [unalignedAccess.jpg]: /images/20210522/f125d44939864f338f95a4d9e247320a.png [Data alignment_ Straighten up and fly right]: http://www.ibm.com/developerworks/library/pa-dalign/ [http_www.cppblog.com_snailcong_archive_2009_03_16_76705.html]: http://www.cppblog.com/snailcong/archive/2009/03/16/76705.html [http_hi.baidu.com_hintonic_blog_item_f6e5a92058d99e6e93580707.html]: http://hi.baidu.com/hintonic/blog/item/f6e5a92058d99e6e93580707.html [http_bbs.ednchina.com_BLOG_ARTICLE_82066.HTM]: http://bbs.ednchina.com/BLOG_ARTICLE_82066.HTM
相关 关于内存对齐 什么是内存对齐 考虑下面的结构: struct foo \{ char c1; short s; char c2; int i; \}; 心已赠人/ 2022年09月18日 05:41/ 0 赞/ 180 阅读
相关 详解内存对齐 `欢迎大家点击上方文字「Golang梦工厂」关注公众号,设为星标,第一时间接收推送文章。` 前言 > 哈喽,大家好,我是`asong`。好久不见,上周停更了一周,因为工 ゝ一纸荒年。/ 2022年09月05日 04:16/ 0 赞/ 205 阅读
相关 内存对齐 typedef struct { char flag[3]; short value; } sampleStruct Bertha 。/ 2022年08月04日 05:17/ 0 赞/ 192 阅读
相关 内存对齐方式 一般我们编程的时候short s=2,int i=4,char c=’a’在内存中是如何对齐的呢? 在32位系统中: ![这里写图片描述][SouthEast] 在 野性酷女/ 2022年06月09日 09:26/ 0 赞/ 273 阅读
相关 C++内存 内存对齐 1 引言 操作系统的内存分配问题与内存对齐问题对于低层程序设计来说是非常重要的,对内存分配的理解直接影响到代码质量、正确率、效率以及程序员对内存使用情况、溢出、泄露等的判断力 男娘i/ 2022年06月08日 05:07/ 0 赞/ 262 阅读
相关 C++内存对齐 内存对齐 在我们的程序中,数据结构还有变量等等都需要占有内存,在很多系统中,它都要求内存分配的时候要对齐,这样做的好处就是可以提高访问内存的速度。 我们还 Bertha 。/ 2022年06月08日 05:07/ 0 赞/ 205 阅读
相关 内存对齐 [详解见CSAPP—-计算机基础—内存对齐讲解,非常清楚一看就懂了][CSAPP_-] [http://blog.csdn.net/cosmoslife/article/de 骑猪看日落/ 2022年06月07日 22:47/ 0 赞/ 195 阅读
相关 内存字节对齐 为什么会有内存对齐 以下内容节选自《Intel Architecture 32 Manual》。 字,双字,和四字在自然边界上不需要在内存中对齐。(对字,双字,和 小鱼儿/ 2022年03月19日 04:38/ 0 赞/ 285 阅读
相关 内存对齐 每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。程序员可以通过预编译命令\pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你 冷不防/ 2022年01月09日 09:21/ 0 赞/ 257 阅读
相关 内存对齐 首先由一个程序引入话题://环境:vc6 + windows sp2 程序1: include "stdafx.h" include <iostream> 我会带着你远行/ 2021年06月11日 15:10/ 0 赞/ 465 阅读
还没有评论,来说两句吧...