iOS底层探索(二)字节对齐

什么是字节对齐

现代计算机中内存空间都是按照byte划分的,从理论上讲彷佛对任何类型的变量的访问能够从任何地址开始,但实际状况是在访问特定类型变量的时候常常在特 定的内存地址访问,这就须要各类类型数据按照必定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。bash

做用和缘由

简单来说是由CPU架构形成的。好比arm64(ARM)x86(Intel、AMD), PowerPC(IBM)等。 做为iOS Developer,常见的有armv7armv7sarm64earm64i386x86_64。 CPU为了高效执行指令或者读取数据,不是按照字节读取的,而是根据数据将内存分块,每块的字节数都是偶数,如 24816字节。每次读取都是一个固定的开销,减小内存存取次数将提高程序的性能。架构

  • 平台缘由(移植缘由):不是全部的硬件平台都能访问任意地址上的任意数据,某些硬件平台只能在某些地址处取某些特定类型的数据,不然抛出硬件异常。
  • 硬件缘由:通过内存对齐以后,CPU的内存访问速度大大提高。

iOS的内存对齐

每一个特定的平台上的编译器都有本身的默认对齐系数(也叫对齐模数)。咱们能够经过预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是要指定的对齐系数。Xcode的对齐系数就是8,GCC对齐系数是4性能

对齐原则

咱们在了解内存对齐以前,先看看内存对齐的原则:spa

  • 数据成员对齐规则:
    Struct 或 union 的数据成员第一个数据成员放在偏移为0的位置,之后每一个成员的偏移为 min(对齐系数,自身长度)的整数倍,不够整数倍的补齐。
  • 数据成员为结构体:
    该数据成员的自身长度为其最大长度的整数倍开始存储
  • 总体对齐规则:
    数据成员按照上述规则对齐以后,其自己也要对齐,对齐原则是min(对其系数,成员最大长度)的整数倍。

翻译一下就是翻译

  • 前面的地址必须是后面的地址整数倍,不是就补齐
  • 结构体里面的嵌套结构体大小要是该嵌套结构体最大元素大小的整数倍
  • 整个Struct的地址必须是最大字节的整数倍

代码求源

接下来,须要用代码验证、查看对象alloc时开辟的真实空间具体是多少。
能够用class_getInstanceSize(class)malloc_size()来打印出对象的大小。code

struct StructOne {
    char a;         //1字节
    double b;       //8字节
    int c;          //4字节
    short d;        //2字节
} MyStruct1;

struct StructTwo {
    double b;       //8字节
    char a;         //1字节
    short d;        //2字节
    int c;         //4字节
} MyStruct2;
NSLog(@"%lu---%lu", sizeof(MyStruct1), sizeof(MyStruct2));
复制代码

获得的结果是24---16对象

StructOne

  • a为1字节,不够8个字节,而第二个成员为b为double类型,为8个字节,因此b能够被编译器单独读取,为了读取效率,不能够分割也不能和其余数据合并,因此要对a进行7个字节补充,使其占用8个字节。
  • c为int类型,占用4个字节,d为short类型,占用2个字节,c和d能够合并另外再对其进行2个字节的补充,使其占用8个字节。 这样就符合了内存对其原则,最后StructOne占用的空间为(1+7)+8+(4+2+2)=24。

StructTwo

  • b占用8个字节
  • a、d、c能够合并,再补充1个字节,使其占用8个字节 最后StructTwo占用的空间为8+(1+2+4+1)=16。

总结

字节对齐是为了提高CPU执行效率产生的规则,原理是按照对齐系数对内存进行排列读取。在iOS中编译器帮咱们处理了这一问题,因此无需考虑,但在平常开发中若是在写C语言的代码时,就能够利用字节对齐的规则进行生命变量,以提高效率。内存

相关文章
相关标签/搜索