iOS九阴真经:三、内存对齐

368 阅读3分钟

通过 alloc源码的探索,已经知道,系统在分配给OC对象内存大小的时候是以16字节对齐的规则进行分配的。

另外,影响对象内存大小的因素是对象的成员变量,方法并不占用对象的内存,属性会占用对象的内存是因为属性除了生成setter和getter之外,还会生成一个成员变量。

一、内存对齐原则

1 数据成员对⻬规则: 结构体(struct)(或联合体(union))的数据成员,第一个数据成员放在 offset 为 0 的地方,以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是数组,结构体等)的整数倍开始(比如int为4字节,则要从4的整数倍地址开始存储。 min(当前开始的位置m n)m=9 n=4 9 10 11 12

  1. 结构体作为成员: 如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储.(struct a 里存有 struct b,b 里有 char,int,double 等元素,那 b 应该从 8 的整数倍开始存储。)

  2. 收尾工作: 结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍,不足的要补⻬。

二、位域、联合体

1. 简单的结构体(struct)

struct SHCar1 {
    BOOL front; // 0 1
    BOOL back;
    BOOL left;
    BOOL right;
};

当前结构体有四个 BOOL 值,一个 BOOL 值占用一个字节所以,SHCar1 共占 4 个字节

2. 结构体位域

struct SHCar2 {
    BOOL front: 1;
    BOOL back : 1;
    BOOL left : 1;
    BOOL right: 1;
};
 
: 1 表示指定这个成员变量占用1位(bit),SHCar2 一共占用4位,所以,SHCar2 占用 1 个字节

注意:

  • 在16位的系统中1字(Word) = 2字节(Byte)= 16(bit)。
  • 在32位的系统中1字(Word) = 4字节(Byte)= 32(bit)。
  • 在64位的系统中1字(Word) = 8字节(Byte)= 64(bit)。

3. 联合体(union)

// 联合体
union SHTeacher1 {
    char *name;
    int  age;
};
// 结构体
struct SHTeacher2 {
    char *name;
    int  age;
};

4. 结构体与联合体的区别

union SHTeacher1 t1;
t1.name = "Andy";
t1.age = 18;

struct SHTeacher2 t2;
t2.name = "Andy";
t2.age = 18;

以上代码,通过lldb打印如下:

联合体打印:
 (lldb) p t1
 (SHTeacher1) $0 = (name = 0x0000000000000000, age = 0)
 (lldb) p t1
 (SHTeacher1) $1 = (name = "Andy", age = 16296)
 (lldb) p t1
 (SHTeacher1) $2 = (name = "", age = 18)
结构体打印:
 (lldb) p t2
 (SHTeacher2) $3 = (name = 0x0000000000000000, age = 0)
 (lldb) p t2
 (SHTeacher2) $4 = (name = "Andy", age = 0)
 (lldb) p t2
 (SHTeacher2) $5 = (name = "Andy", age = 18)

总结:

  1. struct内成员变量的存储互不影响,union内的对象存储是互斥的。
  2. 结构体(struct)中所有的变量是共存的,优点是可以存储所有的对象的值,比较全面。缺点是struct内存空间分配是粗放的,不管是否被使用,全部分配。
  3. 联合体(union)中所有的变量是互斥的,优点是内存使用更加精细灵活,也节省了内存空间,缺点也很明显,就是不够包容。