最近操作系统开始从32位向64位升级,在升级驱动程序的时候发现一个严重的性能问题,后来发现是由于数据对齐引起的,所以查了一下与内存对齐相关的文章,发现了下面的链接:
http://msdn.microsoft.com/en-us/library/83ythb65(v=VS.80).aspx
http://msdn.microsoft.com/en-us/library/Aa290049
根据文章的内容,我们可以得到以下的摘要:
1. 如果不使用__declspec(align(#)),标量会按照它的自然长度进行对齐;
2. 如果不使用__declspec(align(#)),结构体是按着它所有成员的对齐值的最大值进行对齐;
3. 结构体中的成员的起始地址是它前一个元素结束地址后第一个该成员的对齐地址;
4. 结构体的大小是该结构体的实际尺寸圆整到其对齐值的最小整数倍;
5. 如果指定__declspec(align(#)),那么结构体的大小是其自然对齐值和#中较大的值;
6. 如果使用#pragma pack,那么pack中会指定对齐方式;
7. 通常malloc, new, HeapAlloc不能保证正确的堆对齐操作,根据我的实验,通常是8位对齐;
8. 可以通过_alignof()来得到结构体的对齐值;
9. 可以通过_aligned_malloc()来分配内存对齐的内存块。
10. 在x86和x64平台上,数据对齐异常会被CPU自动解决,但是有很大的性能代价,速度会慢2-4倍。
11. 在IA64平台上,OS会把异常传递给应用程序,如果应用不处理,进程终止。
12. 当使用_unaligned关键字,编译器会让内存访问按着字节的方式进行,这样系统不会有问题,但是牺牲效率,速度会慢1-2倍。
要安全绕过数据对齐的问题,可以参考一下几点:
1. 小内存对齐值的指针如果转成大内存对齐值的指针,要保证所有访问对齐。反过来赋值则安全。
2. 尽量不要使用packing,如果使用packing,也不要访问packing过的成员,否则系统就要fix对齐问题。
3. 对齐值一定要设置尽量高,但是又不能过高,因为如果过高结构体的大小就会过大,浪费空间。