c++内存对齐
1.为什么要内存对齐
内存存取粒度:大部分处理器并不是按字节块来存取内存的.它一般会以双字节,四字节,8字节,16字节甚至32字节为单位来存取内存,我们将上述这些存取单位称为内存存取粒度。
以4字节作为存取粒度的处理器,只能从地址为4的倍数的内存开始读取数据。
假如一个int变量存放在从地址1开始的四个字节地址中,该处理器去取数据时,第一次要先从0地址开始读取第一个4字节块,剔除不想要的字节(0地址);第二次从地址4开始读取下一个4字节块,同样剔除不要的数据(5,6,7地址),最后留下的两块数据合并放入寄存器,这会非常影响性能。
归根结底是编译器想通过空间换时间,通过适当增加padding,使每个成员的访问都在一个指令里完成,而不需要两次访问再拼接,提高内存的访问效率。
2.内存对齐规则
对齐系数:#pragma pack(n)。
对齐单位:min(#pragma pack(n),结构体中最长数据类型长度)。
内存对齐规则:
[1]内部对齐:第一个数据成员放在offset为0的地方,以后每个成员相对于结构体首地址的offset都是 min(该成员大小,对齐单位)的整数倍,如有需要编译器会在成员之间加上填充字节。
[2]外部对齐:结构体的总大小为对齐单位的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。
因此看一个结构体大小时,首先根据内部对齐规则累加每个变量的大小,之后再根据外部对齐算出总大小。
例如对于:
1 2 3 4 5 6 7 8 9 | #pragma pack(2) struct aa{ char a; char b; int c; char d; long long e; char f; }; |
首先:对齐单位 = min(#pragma pack(2),sizeof(long long)),因此对齐单位是2。
a放到offset == 0的位置,因为0是【min(a成员大小,对齐单位) == 1】的整数倍。
b放到offset == 1的位置,因为1是【min(b成员大小,对齐单位) == 1】的整数倍。
c放到offset == 2的位置,因为2是【min(c成员大小,对齐单位) == 2】的整数倍。
d放到offset == 6的位置,因为6是【min(d成员大小,对齐单位) == 1】的整数倍。
e放到offset == 8的位置,因为8是【min(e成员大小,对齐单位) == 2】的整数倍。
f放到offset == 16的位置,因为16是【min(f成员大小,对齐单位) == 1】的整数倍。
此时共占用了17个字节,而整个结构体需要是对齐单位(2)的整数倍,因此整个结构体大小是18。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix