内存对齐可以使CPU读取数据效率加快,并且更好的适应各个平台。
假设CPU每次读取4字节(32位系统),在以下情况:
struct
struct MyStruct
{
public:
char c;
int num;
};
若内存对齐,取int值,只需偏移 四字节后读取四字节即可。
此时CPU先访问一次内存,读取0—3字节的数据进寄存器,并再次读取4—5字节的数据进寄存器,接着把0字节和6,7,8字节的数据剔除,最后合并1,2,3,4字节的数据进寄存器。对一个内存未对齐的数据进行了这么多额外的操作,大大降低了CPU性能。
这还属于乐观情况了,内存对齐的作用之一为平台的移植原因,因为以上操作只有有部分CPU肯干,其他一部分CPU遇到未对齐边界就直接罢工了。
如图:
内存对齐规则:
1、第一个元素的存储地址为结构体的首地址,偏移量(offset)为0。
2、其他基本元素(除class/struct/union)存储地址为首地址偏移(offset)一定的偏移量,偏移量为设置的偏移量和其自身元素大小的较小的那个的整数倍(每个元素都是用其自身大小和对齐模数大小做比较)。
structA中含有struct B,则struct B必须以struct中最宽元素的大小为的整数倍开始存储,union必须以起内部最宽元素的大小的整数倍开始存储。
3、结构体的总大小是对齐模数(对齐模数等于#pragma pack(n)所指定的n)与结构体中最大数据类型的成员大小的最小值的整数倍。
class B
{
public:
short al;
double b2;
bool C;
};
关于union的内存对齐:
- 各个元素的首地址的偏移量为 0。
- 当分配好各个元素的空间后,union 自身需要做内存对齐(整体对齐)。将其调整至 union 中占用空间最大的类型所占空间与对齐系数最小的那个值的整数倍即可(在尾部调整)。
即先要找出占用空间最大的类型所占的空间大小,然后求出其与对齐系数的最小值,再将 union 所占空间调整至这个最小值的整数倍即可。