您的位置:首页 > 理论基础 > 数据结构算法

内存对齐的影响因素

2006-11-26 21:01 183 查看
 


)

为什么要有内存对齐


   
以下内容节选自《
Intel Architecture 32 Manual
》。

   
字,双字,和四字在自然边界上不需要在内存中对齐。(对字,双字,和四字来说,自然边界分别是偶数地址,可以被
4
整除的地址,和可以被
8
整除的地址。)

   
无论如何,为了提高程序的性能,数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;然而,对齐的内存访问仅需要一次访问。

   
一个字或双字操作数跨越了
4
字节边界,或者一个四字操作数跨越了
8
字节边界,被认为是未对齐的,从而需要两次总线周期来访问内存。一个字起始地址是奇数但却没有跨越字边界被认为是对齐的,能够在一个总线周期中被访问。

   
某些操作双四字的指令需要内存操作数在自然边界上对齐。如果操作数没有对齐,这些指令将会产生一个通用保护异常(
#GP
)。双四字的自然边界是能够被
16
整除的地址。其他的操作双四字的指令允许未对齐的访问(不会产生通用保护异常),然而,需要额外的内存总线周期来访问内存中未对齐的数据。



)

常见数据类型的内存对齐


为了能使
CPU
对变量进行高效快速的访问,变量的起始地址应该具有某些特性,

即所谓的

对齐

。例如对于
4
字节的
int
类型变量,其起始地址应位于
4
字节边界上,

即起始地址能够被
4
整除。变量的对齐规则如下(
32
位系统):

Type

Alignment(
默认的自然对齐
)

char

在字节边界上对齐

short(16-bit)

在双字节边界上对齐

int  long (32-bit)


4
字节边界上对齐

float


4
字节边界上对齐

double


8
字节边界上对齐

structures


单独考虑结构体的每个成员,它们在不同的字节边界上对齐。
其中最大的字节边界数就是该结构的字节边界数

 

structures


对于结构体
S1
的每个简单成员如果其对齐边界是
x1,
而它又含有结构体
S2,

S2
内部的对齐边界是
x2,
则结构体
S1
的对齐边界取
X=max(x1, x2);

对于结构体
S2
中的某一成员
item
,它的对齐边界取
: X=max(sizeof(item)

 

范例:


struct s1{

short a; 

long b;

};

struct s2{

char c;

s1 d;

long long e;

};



1.sizeof(s2) = ?

2.s2
的内存布局是怎么样的
?

答:

 //modify 2007.3.10

s1,
成员
a

short,

2byte
自然对齐
;
成员
b

int,

4byte
自然对齐,取最大成员的
size(int),
因此这个结构体的对齐边界就是
4bytes.
所以
sizeof(s1)=8;

s2,
成员
c

char,

1byte
自然对齐。但成员
d
则又是个结构体,
sizeof(d)

8byte,
结构体
d
内成员的最大是
int,
它的内部对齐由
s1
可知,是按
4byte
对齐。那么这边又按什么对齐呢?下面成员
e

long long,
默认按
8byte
对齐。因此
S1
中的成员是按
8BYTE
对齐
,

S2
中仍然按照
4BYTE
对齐
.

a b

S1
的内存布局:
11**,1111,      
//4byte
对齐, sizeof(s1)=2+[2]+4 = 8  

S2
的内存布局:
1***,****,11**,1111,11111111 //8byte
对齐, sizeof(s2)=1+[7]+8+8 = 24byte.

实际gcc下检测得到的是20byte=1+[3]+8+8, 估计是按4byte缺省对齐的。

说明:[ ]表示需要补位的值。Modify on Mar,5,2010.
------------------------------------------------------------------------------------

 

 

注意:

1


对于空结构体,
sizeof
==
1
;因为必须保证结构体的每一个实例在内存中都

有独一无二的地址。

2


结构体的静态成员不对结构体的大小产生影响,因为静态变量的存储位置与

结构体的实例地址无关。

例如:

struct {static int I;} T; struct {char a; static int I;} T1;

sizeof(T) == 1; sizeof(T1) == 1;

 



)

各编译器下内存对齐的影响


上面那种是系统默认的对齐,也就是自然对齐。

现实中,编译器也能按指定的字节进行对齐,这称为指定对齐。如
VC

gcc

--------------------------------MSDN VC----------------------------------------------------

   
使用伪指令
#pragma pack (n)
,编译器将按照
n
个字节对齐;

   
使用伪指令
#pragma pack ()
,取消自定义字节对齐方式。

#pragma pack(n)

When you use #pragma pack(n), where n is 1, 2, 4, 8, or 16, each structure member after the first is stored on the smaller member type or n-byte boundaries. If you use #pragma pack without an argument, structure members are packed to the value specified by /Zp. The default /Zp packing size is /Zp8.

----------------------------------GCC-----------------------------------------------

__attribute__ ((packed));
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息