内存对齐原因和规则
2023-04-18 13:11:38 时间
结构体中的元素在内存中并不是紧密排列的,原因在于CPU从内存取数据时,是一次取多个字节的,可以将内存看做多个抽屉,如每个抽屉中存放4字节,此时如果要取一个4字节的int值,如果该int值不在一个抽屉中而是一个抽屉里各存放一部分字节(即没有内存对齐),就需要读取两次内存内容(开两次抽屉)才能取到完整的int值,对性能有影响,甚至有些硬件架构下,不能访问任意地址的数据,只能从某些地址下才能访问特定类型的数据,否则会报错。
对齐规则1:结构体中的每个成员必须存放在该成员大小的整数倍偏移处。
对齐规则2:结构体大小必须是其最大元素的整倍数。
为了对齐而空出来的字节填0。
如以下结构体:
struct s1 {
char c1; // char大小为1字节,需要存放在1的整数倍处,即可存放在任意地址处,此处的c1存放在偏移量0处
int i1; // int大小为4字节,因此需要存放在4的整数倍处,因此c1和i1之间有3字节的0填充,此处的i1存放在偏移量4处
char c2; // char大小为1字节,需要存放在1的整数倍处,即可存放在任意地址处,此处的c2存放在偏移量8处
int i2; // int大小为4字节,因此需要存放在4的整数倍处,因此c2和i2之间有3字节的0填充,此处的i1存放在偏移量12处
char c3; // char大小为1字节,需要存放在1的整数倍处,即可存放在任意地址处,此处的c3存放在偏移量16处
// c3后需要将结构体大小补齐到最大元素整数倍,未补齐时结构体大小为17字节,结构体中最大元素大小为4,因此结构体最后需要补3字节的0到20字节
};
以上结构体在内存中的大小是20字节而非简单的元素大小之和(11字节)。
结构体中的元素顺序不同,结构体在内存中的大小也不同:
struct s2 {
char c1; // char大小为1字节,需要存放在1的整数倍处,即可存放在任意地址处,此处的c1存放在偏移量0处
char c2; // char大小为1字节,需要存放在1的整数倍处,即可存放在任意地址处,此处的c2存放在偏移量1处
char c3; // char大小为1字节,需要存放在1的整数倍处,即可存放在任意地址处,此处的c3存放在偏移量2处
int i1; // int大小为4字节,因此需要存放在4的整数倍处,因此c3和i1之间有1字节的0填充,此处的i1存放在偏移量4处
int i2; // int大小为4字节,因此需要存放在4的整数倍处,此处的i1存放在偏移量8处
};
以上交换元素顺序后的结构体大小为12字节。
我们可以使用预编译命令#pragma pack(n)
来将对齐模数设为n,对齐模数指的是:如果是int数据,则对齐模数是4,如果是double数据,则对齐模数是8。如果将结构s1的对齐模数设为2:
#pragma pack(2)
struct s3 {
char c1; // c1存放在偏移量0处
int i1; // int大小为4字节,对齐模数为2,i1会存放在地址2处,c1和i1之间只有1字节的0填充
char c2; // c2存放在偏移量6处
int i2; // int大小为4字节,对齐模数为2,i1会存放在地址8处,c2和i2之间只有1字节的0填充
char c3; // c3存放在偏移量12处
// c3后需要将结构体大小补齐到对齐模数的整数倍处,未补齐时结构体大小为13字节,因此结构体最后需要补1字节的0到14字节
};
注意#pragma pack(n)
的目的是让结构体更紧凑,如果n比默认应该空余的字节数要大,则按应该空余的字节数来计算,s3的结构体最后填补了1个字节而非3个字节就是这个原因,如:
#pragma pack(8)
struct s4 {
char c; // c存放在偏移量0处
int i; // i如果按pack的参数来计算,应该存在偏移量8处,会填充7个0字节,超出了默认填充3个0字节,因此会填充3个0字节
};
以上结构体的大小为8而非16。
相关文章
- 【技术种草】cdn+轻量服务器+hugo=让博客“云原生”一下
- CLB运维&运营最佳实践 ---访问日志大洞察
- vnc方式登陆服务器
- 轻松学排序算法:眼睛直观感受几种常用排序算法
- 十二个经典的大数据项目
- 为什么使用 CDN 内容分发网络?
- 大数据——大数据默认端口号列表
- Weld 1.1.5.Final,JSR-299 的框架
- JavaFX 2012:彻底开源
- 提升as3程序性能的十大要点
- 通过凸面几何学进行独立于边际的在线多类学习
- 利用行动影响的规律性和部分已知的模型进行离线强化学习
- ModelLight:基于模型的交通信号控制的元强化学习
- 浅谈Visual Source Safe项目分支
- 基于先验知识的递归卡尔曼滤波的代理人联合状态和输入估计
- 结合网络结构和非线性恢复来提高声誉评估的性能
- 最佳实践丨云开发CloudBase多环境管理实践
- TimeVAE:用于生成多变量时间序列的变异自动编码器
- 具有线性阈值激活的神经网络:结构和算法
- 内网渗透之横向移动 -- 从域外向域内进行密码喷洒攻击