Linux程序调试--内存地址对齐

改编自:

http://blog.youkuaiyun.com/donkeylong/archive/2009/12/01/4909720.aspx

一,内存地址对齐的概念

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

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

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

二,不进行对齐的影响

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

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

结构体本身必须是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指令。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值