字节对齐的目的是什么?
1.增加内存利用率
2.增加程序的运行效率
但这两点有时候在内存对齐时却是相互违背的。比如我们来对比下面的程序,在此之前声明一下我的环境,x86(P4),VC 2005:
程序1
#pragma pack(4)
class A
{
public:
char a;
int aa;
};
程序2
#pragma pack(1)
class B
{
public:
char a;
int aa;
};
类A的size是8,而B的size是5,A相对于B来说浪费了内存空间,但同时我们还要看看对于A和B中的成员aa,aa的地址在类A中是可以被4整除(即:addr(A::aa)%4=0),而aa在类B中由于内存对齐方式是1,所以aa的地址无法被4整除(即:addr(A::aa)%4!=0).那么由于在x86(32位)上,从无法被4整除的地址边界去访问变量,会影响效率,具体原因已经超出了本文的讨论范围,以后用另一篇文章讨论.这里只放一个测试用例,如果有兴趣的朋友可以运行一下(VC 2005):
测试用例1:
inline unsigned __int64 GetCycleCount(void)
{
_asm _emit 0x0F
_asm _emit 0x31
}
int _tmain(int argc, _TCHAR* argv[])
{
long long l = 3000000000000;
unsigned __int64 begin = GetCycleCount();
for(long long i = 1000000000; i > 0; i--)
{
// Empty the cache in CPU.
l--;
// Access the memory as the address can be divided by 4
__asm
{
mov ecx,dword ptr [l]
}
}
unsigned __int64 end = GetCycleCount();
printf("The elapse time is:%I64d\n", end - begin);
return 0;
}
测试用例2:
inline unsigned __int64 GetCycleCount(void)
{
_asm _emit 0x0F
_asm _emit 0x31
}
int _tmain(int argc, _TCHAR* argv[])
{
long long l = 3000000000000;
unsigned __int64 begin = GetCycleCount();
for(long long i = 1000000000; i > 0; i--)
{
// Empty the cache in CPU.
l--;
// Access the memory as the address can not be divided by 4
__asm
{
mov ecx,dword ptr [l+1]
}
}
unsigned __int64 end = GetCycleCount();
printf("The elapse time is:%I64d\n", end - begin);
return 0;
}
比较测试用例1与测试用例2打印出来的时间,你就可以从直观上得到访问奇地址时效率上的损失.
所以我的结论是:
在使用字节对齐时,请仔细考虑你要的是效率还是要的是内存,并在写程序时注意。