OC底层探究(2)--内存对齐

2019-12-22  本文已影响0人  墨守青城

一、何为内存对齐

内存对齐”应该是编译器的“管辖范围”。编译器为程序中的每个“数据单元”安排在适当的位置上。但是C语言的一个特点就是太灵活,太强大,它允许你干预“内存对齐”。如果你想了解更加底层的秘密,“内存对齐”对你就不应该再模糊了。

二、如何内存对齐

每个特定平台上都有自己的默认“对齐系数”(也叫对齐模数)。程序员可以通过[预编译]命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。ios中默认系数为8。

对齐规则:

  1. 数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照min(对齐系数,自身长度)进行。
  2. 结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照min(对齐系数,最大数据成员长度)进行。
    下面举个🌰:
struct Struct1 {
    char a;     // 1
    double b;   // 8
    int c;      // 4
    short d;    // 2
} MyStruct1;

struct Struct2 {
    double b;   // 8
    int c;      // 4 
    char a;     /
    short d;    // 2
} MyStruct2;

NSLog(@"%lu-%lu",sizeof(MyStruct1),sizeof(MyStruct2));

上面的输出结果为:

24-16

那么是为什么两个结构体的大小输出不一致呢,我们可以按照上面的两条原则进行分析。
先分析Struct1:

分析完Struct1,即可同理分析出Struct2的大小了。

三、为何要内存对齐

  1. 平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
  2. 性能原因:经过内存对齐后,CPU的内存访问速度大大提升。具体原因请往继续下看。
    在普通程序员心目中的内存印象,由一个个的字节组成,而CPU并不是这么看的。CPU把内存当成是一块一块的,块的大小可以是2,4,8,16字节大小,因此CPU在读取内存时是一块一块进行读取的。块大小成为memory access granularity(内存读取粒度) 。
    举个🌰假设CPU要读取一个int型4字节大小的数据到寄存器中,分两种情况讨论:
    a. 数据从0字节开始
    当该数据是从0字节开始时,很CPU只需读取内存一次即可把这4字节的数据完全读取到寄存器中。
    b.数据从1字节开始
    当该数据是从1字节开始时,问题变的有些复杂,此时该int型数据不是位于内存读取边界上,这就是一类内存未对齐的数据。此时CPU先访问一次内存,读取0—3字节的数据进寄存器,并再次读取4—5字节的数据进寄存器,接着把0字节和6,7,8字节的数据剔除,最后合并1,2,3,4字节的数据进寄存器。对一个内存未对齐的数据进行了这么多额外的操作,大大降低了CPU性能。当然,实际情况可能更复杂。
上一篇下一篇

猜你喜欢

热点阅读