大话C++之:内存对齐

在使用sizeof()计算结构体和class大小的时候,往往很多时候计算出来并不是我们想要的结果。最近在使用的时候就特别想了解它内在的原理,搞懂它的本质。
看一下下面这个例子:

struct Struct{
	char a;
	int i;
};

问题是:这个结构体大小是多少?
很多人回答可能是5个字节。分析结构体的组成是:char占1个字,int占4个字节。1+4=5,没错吧?
其实这个答案应该是:不确定。因为它给的条件不能够得出一个确定的答案。
打开VS 2017,64位程序执行一下,得出的结果是8。
既然它不是简单的把成员大小简单累加,想必它肯定是有一套规则,那是什么规则呢?那就是内存对齐

  1. (what)什么内存对齐(Data alignment)?
    百度百科的定义:编译器为程序中的每个“数据单元”安排在适当的位置上。
    我的理解是按照一定的规则把它的位置排好,排列得有规有矩,方便计算机读取。

  2. (why)为什么要使用内存对齐
    为了性能
    性能:为什么内存对齐为提高性能呢?举个例子,例如把4个字节从地址1写入到寄存器中。首先从前4个字节中读取3个节字,再从后面4个字节中读了1个字,最后放在寄存器中合并在一齐。读取一个数据到寄存器中消耗了这么多步骤,对于CPU性能来说是挺大的负担。如果是字节对齐了,从0开始连续读取4个字,寄存器刚好也是4个字节,只需要一次读写即可,大大提高了读取效率。
    图1
    图2

  3. (how)内存对齐是如何工作的
    想想我们平时要把物品整理对齐的时候,一般都有参照物或对齐的标准。如果把箱子排好,是一个个紧密对齐排列呢,还是间隔排列呢,这个标准会影响排列后使用的空间。
    对于内存对齐,同样也是有一个参考标准。编译器中提供了#pragma pack(n)来设定变量以n字节对齐方式,n即为对齐的标准。
    VS 2017 64bit的字节对齐变量为16,在代码中插入:#pragma pack(show),就可以查看当前环境的变量值。
    有了这个标准,还需要的是被排列的对象:字段类型。
    拿回箱子排列的例子来说,可能每一个箱子的大小不一样,有些是短一点,有些是长一点,可能排列的位置也有不一样。
    箱子大小就如成员变量,每一个变量有自己的大小。
    现在来看一步步分解,系统是如何把位置给安排得明明白白的。
    例如这个

struct Struct{
	char a;
	int i;
};
  • 每一块内存内存是从0开始偏移的,第一个字段直接安排下去。
    第一个字段char,偏移量(offset)为0,占用空间1个字节,结束位置为1;
字段类型字段名字段偏移量字段占用大小字段结束位置
chara011
  • 关键一步来了,如何安排int字节呢?
    a.int字节是4 bytes,字节对齐变量为16 bytes。比较两者间选择小的一个,此时4 bytes作为偏移参考量X。
    b.从当前偏移量1开始,寻找偏移参考量X最小的倍数位置。4的倍数可以是,4,8,12,16等等,当前最小的为4。然而1,2,3的位置空了,需要填充,从第4个byte开始连续4个byte为int的空间。
    c.此时8个字节的排布为:a—iiii;
    d.画重点:char型占用空间为1 byte,则其起始位置必须可被1整除。int为4 bytes,其起始位置必须是可以被4整除。
字段类型字段名字段偏移量字段占用大小字段结束位置
chara011
padding112
padding113
padding114
inti448
总的内存大小8
  • 内存对齐的过程如上,影响同一个结构体的内存布局的关键是:以多少字节来对齐,如上面所说的n。最开始的例子,实际上可以通过设置n为1,可以得到size为5。
    回顾一下最开始的问题,缺少一个指定变量n的条件,故不能确定大小是多少。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值