内存对齐

什么是内存对齐

在C/C++中,结构体实际占用内存大小不总是等于各成员变量占用内存的和,例如下面代码

#include <stdio.h>
#include <stdlib.h>

struct test01{
    int x;
    char y;
    char z;
};

struct test02{
    char y;
    int x;
    char z;
};

struct test03{
    char y;
    char z;
    int x;
};

int main(){

    struct test01 example01;
    struct test02 example02;
    struct test03 example03;

    printf("%d\n",sizeof(example01));//输出结果 8
    printf("%d\n",sizeof(example02));//输出结果 12
    printf("%d\n",sizeof(example03));//输出结果 8

    system("pause");
    return 0 ;
}

注意到,结构体中成员相同,输出占用内存却不相同,在32为系统下,int 占用4字节,char占用1字节,理论上结构体应该占用6字节才对,但事实并非如此。

现代计算机内存都是按字节划分的,理论上来说任意类型的变量可以从任意位置开始访问,但是实际的计算机系统对基本类型数据在内存中存放的位置有限制,它们会要求这些数据的首地址的值是某个数k(通常它为4或8)的倍数,这就是所谓的内存对齐。

为什么要内存对齐

内存对齐是操作系统为了提高访问内存的策略。操作系统在访问内存的时候,每次读取一定长度(这个长度是操作系统默认的对齐数,或者默认对齐数的整数倍)。如果没有对齐,为了访问一个变量可能产生二次访问。

尽管内存是以字节为单位,但是大部分处理器并不是按字节块来存取内存的.它一般会以字(word)为单位来读取内存,一个字可以是2字节、4字节、8字节,我们将上述这些存取单位称为内存存取粒度。现在考虑4字节存取粒度的处理器取int类型变量(32位系统),该处理器只能从地址为4的倍数的内存开始读取数据。假如没有内存对齐机制,数据可以任意存放,现在一个int变量存放在从地址1开始的连续四个字节地址中,该处理器去取数据时,要先从0地址开始读取第一个4字节块,剔除不想要的字节(0地址),然后从地址4开始读取下一个4字节块,同样剔除不要的数据(5,6,7地址),最后留下的两块数据合并放入寄存器.这需要做很多工作。

现在有了内存对齐的,int类型数据只能存放在按照对齐规则的内存中,比如说0地址开始的内存。那么现在该处理器在取数据时一次性就能将数据读出来了,而且不需要做额外的操作,提高了效率。

内存对齐规则

#pragma pack(show)
显示当前packing alignment的字节数,以warning message的形式被显示。
#pragma pack(n)
指定packing的数值,以字节为单位,缺省数值是8,合法的数值分别是1,2,4,8,16。

每个平台上的编译器都有默认对齐系数(也称为对齐模数),在gcc下默认是4

有效对齐值:是给定值#pragma pack(n)和结构体中最长数据类型长度中较小的那个。有效对齐值也叫对齐单位。

  1. 数组成员对齐规则。第一个数组成员应该放在偏移量(offset)为0的地方,以后每个数组成员应该放在offset为min(当前成员的大小,有效对齐值)整数倍的地方开始(比如int在32位机器为4字节,#pargama pack(2),那么从2的倍数地方开始存储)。
  2. 结构体总的大小,也就是sizeof的结果,必须是min(结构体内部最大成员,#pargama pack(n))的整数倍,不足要补齐。
  3. 结构体做为成员的对齐规则。如果一个结构体B里嵌套另一个结构体A,还是以最大成员类型的大小对齐,但是结构体A的起点为A内部最大成员的整数倍的地方。(struct B里存有struct A,A里有char,int,double等成员,那A应该从8的整数倍开始存储。),结构体A中的成员的对齐规则仍满足原则1、原则2。

对开头的例子进行分析,example01,有效偏移量为4(#pragma packing(n)和int均为4),第一个int 存储在offset为0的起始位置0,第二个成员char大小为1<有效对齐值,偏移1的倍数即可,故第二个char存储在位置4,第三个成员char同理存储在地址为5的位置,成员对齐完成后,进行结构体总大小的对齐,取有效对齐值的整数倍8,故example01占用8个字节。

example02,有效对齐值取4,第一个成员char存储在offset为0的位置0,第二个成员int大小与有效对齐值取值相同,故应offset应该取值为4,int存储在地址为4的位置。第三个成员char大小为1< 有效对齐值,故offset取1的整数倍即可,char存储在地址为8的位置,共占用了9个字节,此时结构体成员对齐完毕,对结构体整体进行对齐,取有效对齐值的最小整数倍12,故结构体变量example02占用12个字节大小。

下图为开头三个例子在内存中分布图
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值