OC底层——结构体内存对齐

前言

这篇文章中OC底层——alloc分析我们提到过一个align16 16字节对齐算法,下面我们就来探索下内存对齐原则。

内存对⻬的原则

1、数据成员对⻬规则:结构( struct )(或联合(union))的数据成员,第
⼀个数据成员放在 offset 为0的地⽅,以后每个数据成员存储的起始位置要
从该成员⼤⼩或者成员的⼦成员⼤⼩(只要该成员有⼦成员,⽐如说是数组,
结构体等)的整数倍开始(⽐如int为4字节,则要从4的整数倍地址开始存
储。 min(当前开始的位置m n) m = 9 n = 4
9 10 11 12
2、结构体作为成员:如果⼀个结构⾥有某些结构体成员,则结构体成员要从
其内部最⼤元素⼤⼩的整数倍地址开始存储.( struct a⾥存有 struct b,b
⾥有 char,int ,double 等元素,那b应该从8的整数倍开始存储.)
3、收尾⼯作:结构体的总⼤⼩,也就是 sizeof() 的结果,.必须是其内部最⼤
成员的整数倍.不⾜的要补⻬。
 

下图为各种数据类型所占的字节大小

结构体内存对齐

下面用实例来解释内存对齐原理:

#import <objc/runtime.h>

// 结构体内存对齐
struct LGStruct1 {
    double a;       // 8    [0 7]
    char b;         // 1    [8]
    int c;          // 4    (9 10 11 [12 13 14 15]
    short d;        // 2    [16 17] 24
}struct1;

struct LGStruct2 {
    double a;       // 8    [0 7]
    int b;          // 4    [8 9 10 11]
    char c;         // 1    [12]
    short d;        // 2    (13 [14 15] 16
}struct2;

struct LGStruct3 {
    double a;       // 8     [0 7]
    int b;          // 4     [8 9 10 11]
    char c;         // 1     [12]
    short d;        // 2     (13 [14 15]
    int e;          // 4     [16 17 18 19 20]
    struct LGStruct1 str;    //24  44-> 48
}struct3;

NSLog(@"%lu-%lu-%lu",sizeof(struct1),sizeof(struct2),sizeof(struct3));
结果:
24-16-48

通过打印结果,我们发现LGStruct1和LGStruct2结构体中变量的数量和类型都是一样的,只是顺序不同,但是所占用的内存空间却完全不同,这就是因为内存对齐原理造成的。

再看LGStruct3,结构体嵌套结构体:LGStruct3结构⾥有某些结构体成员,则结构体成员要从

其内部最⼤元素⼤⼩的整数倍地址开始存储.(struct3中最大变量为str, 其最大成员内存字节数为8,根据内存对齐原则,所以struct3实际的内存大小必须是8的整数倍,LGStruct1的内存大小是24,所以20 + 24 == 44 结构体8字节对齐原则 LGStruct3 内存大小为48 )
 

获取内存大小的3种方式

LGPerson *person = [LGPerson alloc];
person.name      = @"LG";
person.nickName  = @"lg";
person.age       = 21;
person.height    = 180;
        
NSLog(@"%@\n - sizeof打印:%lu\n - class_getInstanceSize打印:%lu\n - malloc_size打印:%lu",person,sizeof(person),class_getInstanceSize([LGPerson class]),malloc_size((__bridge const void *)(person)));

输出结果:
<LGPerson: 0x600002fbc180>
 - sizeof打印:8
 - class_getInstanceSize打印:48
 - malloc_size打印:48

sizeof()

  • 是一个判断数据类型或者表达式长度的运算符,而不是一个函数;
  • 其作用就是返回一个对象或者类型所占的内存字节数;
  • 编译器对 sizeof() 的处理都是在编译阶段进行。

class_getInstanceSize()

  • 该方法在OC底层——alloc分析中分析_class_createInstanceFromZone源码实现中,已经进行过简单的了解。

  • 其本质是获取创建的对象至少所需的内存大小,8字节对齐。

malloc_size()

  • 堆空间实际分配给对象的内存大小,并且按照16字节对齐,我们可以看到实际分配的内存大小和实际所需的内存大小并不相等。后面有时间会再出一篇详细malloc源码分析的文章,具体分析一下malloc流程。

系统的自我(内存)优化

待...


 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值