linux内存对齐

一,内存地址对齐的概念

   计算机内存中排列、访问数据的一种方式,包含基本数据对齐和结构体数据对齐。

   32位系统中,数据总线宽度为32,每次能够读取4字节数据。地址总线为32,最大寻址空间为4GB。但是由于最低位A[0]~A[1]是不用于寻址的,因此只能访问4的倍数的地址空间,但是寻址空间还是2^30*字长=4GB。

  因此内存中除了结构体中成员变量之外的基本类型的开始的手地址最低两位都是0。基本类型数据对齐就是数据在内存中的偏移地址必须是一个字的倍数,以提高读取数据时的性能。为了对齐数据,必须在上个数据结束和下个数据开始处插入一些字节,这就是结构体数据对齐。

二,内存对齐的原因

大部分的参考资料都是如是说的:
1、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据 的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2、性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。 原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

  例如int a的地址是0x00fffff3,则其字节分布在0x00fffff3~0x00fffff6空间内,为了读取这个int,cpu必须对 0x00fffff0和0x00fffff4进行两次内存读取,并处理得出的中间结果。两次内存访问将会浪费大量的时间,因为内存访问的速度远小于CPU 处理指令的速度。

 

 

、对齐规则
每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。程序员可以通过预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。

规则:
1、数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后 每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。
2、结构(或联合)的整体对齐规则:在 数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。
3、结合1、2颗推断:当#pragma pack的n值等于或超过所有数据成员长度的时候,这个n值的大小将不产生任何效果。

四,结构体的内存地址对齐

 

  结构体本身必须是4字节对齐的,而其成员变量则处理规则如下。

 

  以下是Microsoft和GNU对x86架构32位系统的结构体成员的默认对齐方式:

 

  char  1字节对齐

  short  2字节对齐

  int      4字节对齐

  float  4字节对齐

 double windows是8字节对齐,linux是4字节对齐

 

 当某一个成员后边的成员变量要求的地址对齐较大,则应该填入一些字节。且总的结构体大小为最大对齐的倍数,因此最后可能还要填充一些字符。

 

  因为上述结构体对齐的原因,将结构体成员按照大小递增/递减方式排序,可以减少结构体占用的空间大小。而这样同时使得对整个结构体的存取的效率变高了(占用小,整个的访问次数可以降低)。

 

 另外一个提高效率的方法是把一些占用字节数较少的成员合并到字节数占用大的成员,形成union类型。比如,

 

struct Merge{

 

int b; 

union {

 

  int a;

  char b;

  } 

 }

占用为8字节。初始化需要3次内存读,3次赋值,3次内存写。

struct UnMerge{

 

int b;  

  int a;

  char b;

 }

 占用为12字节。初始化需要2次内存读,3次赋值,1次位移,2次内存写。

 但是用CPU的操作换取内存的读写可以很大的提高性能。基本上提高的性能比例等于内存访问次数的较少数目和当前访问次数的比例,此处为(6-4)/4=50%。

 数组或者结构体数组只要保证首地址对齐,其中元素不要求对齐,因为对于数组,其中任何元素都可以在1~2次内存访问中获取,对于结构体数组,因为结构体内部是按照上述方式填充,则也不需要结构体数组的元素都地址对齐。

  对于性能要求较高的情况,比如tcp/ip协议的首部的定义,可以采用位段(bit-fields)的方式来对整数数据按照需要的字段数分配。当然,位段 只能对整数进行操作,如果float和int类型数据放在一起用位段方式显然不行,但是通过位移的方法也可以把char类型数据并入float或者 double中。位段也需要遵循结构体对齐的方式。

五,用户自定义

  使用#pragma pack指令。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值