美文网首页
IOS底层(六): alloc相关: 内存对齐

IOS底层(六): alloc相关: 内存对齐

作者: ShawnAlex | 来源:发表于2021-03-24 19:44 被阅读0次

OC底层源码/原理合集

建议先看下
IOS底层(三): alloc相关1.初探 alloc, init, new源码分析,
IOS底层(四): alloc相关: 对象属性在内存中的布局

首先先介绍IOS中3种获取内存方法

  • sizeof
  • class_getInstanceSize
  • malloc_size

sizeof

sizeof得到的是: 数据类型占用空间的大小

sizeof是一个操作符, 不是函数, 我们一般用sizeof计算内存大小时, 传入的主要对象是数据类型, 这个在编译器的编译阶段就会确定而不是运行时确定。

class_getInstanceSize

class_getInstanceSize 得到的是: 实例对象中成员变量的内存大小

class_getInstanceSizeruntime提供的api, 用于获取类的实例对象所占用的内存空间的大小, 并返回具体的字节数。

malloc_size

class_getInstanceSize 得到的是: 系统实际分配的内存大小

这个是由系统完成的, 涉及16字节内存对齐

三种获取内存方法打印结果

关于字节对齐, 我之前写的都是类的, 这次看下结构体的字节对齐, 例:

        struct Mystruct1 {
            char a;     // 1字节
            double b;   // 8字节
            int c;      // 4字节
            short d;    // 2字节
        } Mystruct1;
        
        struct Mystruct2 {
            double b;
            int c;
            short d;
            char a;
        } Mystruct2;
        
        NSLog(@"结构体1占用的内存大小 %lu", sizeof(Mystruct1));
        NSLog(@"结构体2占用的内存大小 %lu", sizeof(Mystruct2));
结果

为什么会是这个样子呢? 看到这个结果至少2个问题

  • 1.这个内存是怎么计算的?
  • 2.结构体1跟2的区别只是换了一个char位置, 为什么内存会变?

内存对齐原则

  • 每个平台的编辑器都有自己的对齐系数, 程序员也可以通过预编译命令#pragma pack(n), n=1,2,4,8,16来改变这一系数, 其中n就是你指定的对齐系数。在ios中xcode默认为8, 即8字节对齐

  • 数据成员对齐可以理解为min(m, n)公式, 其中m表示当前成员开始位置, n表示当前成员所需要的位数。如果满足 m 整除 n (m % n == 0), nm位置开始存储, 反之m循环+1, 直至可以整除, 从而确定了当前成员位置。

  • 数组成员为结构体, 当结构体嵌套结构体时, "成员"的结构体的自身长度为"成员"结构体中最大成员的内存大小, 例如结构体a嵌套结构体b,b中有char、int、double等,则b的自身长度为8

  • 结构体的内存大小必须为结构体最大成员内存大小的整数倍, 不足需要补齐

验证内存对齐原则

先看下ios中数据类型的占用内存大小, 方便我们之后计算


字节数对照表

针对于上面那个例子, 先看下这个图便于理解


结构体例子计算
结构体1
  • a: char类型占1字节, 因为 0 % 1 = 0, 即, 0储存a
  • b: double类型占8字节,
    1 % 8 = 1, 不满足 +1,
    2 % 8 = 2, 不满足 +1
    ......
    8 % 8 = 0, 满足, 8储存b
  • c: int类型占6字节, 16 % 4 == 0, 16存储c
  • d: short类型占2字节, 20 % 2 == 0, 20存储d

结构体1需要内存22, 由于最大字节数为8, 结构体必须是8的倍数, 所以需要向上取整, 固最终结果为24

结构体2
  • b: double类型占8字节, 0 % 8 == 0, 0储存b
  • c: int类型占6字节, 8 % 4 == 0, 8存储c
  • d: short类型占2字节, 12 % 2 == 0, 12存储d
  • a: char类型占1字节, 因为 14 % 1 = 0, 即, 14储存a

结构体1需要内存15, 由于最大字节数为8, 结构体必须是8的倍数, 所以需要向上取整, 固最终结果为16

之前的问题解决了, 我们接下来看下结构体嵌套结构体

结构体嵌套结构体
        struct Mystruct1{
            char a;     //1字节
            double b;   //8字节
            int c;      //4字节
            short d;    //2字节
        }Mystruct1;

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

        struct Mystruct3 {
            double b;
            int c;
            short d;
            char a;
            struct Mystruct2 str;
        } Mystruct3;

看下结构体3(结构体3为结构体2基础上嵌一个结构体2), 如果按照我们之前的定义

  • 结构体2为16, 且最大字节数8, 那么作为成员结构体2, 字节数为也为8, 结构体3最大字节数为8

  • str: struct类型占16字节, 16 % 16 == 0, 固从16起

结构体3需要内存32, 由于最大字节数为8, 结构体必须是8的倍数, 32满足, 不需要取整, 固结果应为32, 我们验证一下

结构体嵌结构体 结构体嵌入结构体例子计算

我们再做一下验证一下

      struct Mystruct4{
            int a;
            struct Mystruct5{
                double b;
                short c;
            }Mystruct5;
        }Mystruct4;
  • 先看内嵌结构体5中最大为double, 8字节,
    0 % 8 = 0, 0开始放doubleb,
    8 % 2 = 0, 8放shortc, 别忘了整体需要最大值整数倍, 那么结构体5需要16字节

  • 结构体4中, 首先最大为结构体5的8字节,
    0 % 4 = 0, 0开始放inta,
    8 % 8 = 0, 8开始放 结构体5, 总共需要 24

  • 因为24是8的整数倍, 故占用内存大小为24

验证一下


结构体嵌结构体

内存优化(属性重排)

上面我们看到结构体1与结构体2里面属性是一样的, 只有排列位置不一样, 结果占用内存结果也不一样。所以结构体内存大小与结构体成员内存大小的顺序有关

  • 如果是结构体中数据成员是根据内存从小到大的顺序定义的,根据内存对齐规则来计算结构体内存大小,需要增加有较大的内存padding即内存占位符,才能满足内存对齐规则,比较浪费内存

  • 如果是结构体中数据成员是根据内存从大到小的顺序定义的,根据内存对齐规则来计算结构体内存大小,我们只需要补齐少量内存padding即可满足堆存对齐规则,这种方式就是苹果中采用的,利用空间换时间,将类中的属性进行重排,来达到优化内存的目的

结构体的看完了, 我们看下类中的属性重排, 例如我们定义一个SATest

属性重排例子

main中给一些值, 然后我们读一下内存

属性重排例子

这个我们我们可以看到 name, age, hobby都读到可, 但是height, c1, c2并没有读取到, 而且isa旁边的内存段读出来是一串数字?

原因是由于苹果系统对属性进行重排, 0x0000001200006261这一串就是age, c1, c2age占4个字节,c1,c2占1个字节,通过4+1+1的方式,按照8字节补齐的方式存储在同一块内存中, 我们打印一下

属性重排例子

这里留意一下char类型是以ASCII码形式显示, 而地址为0x0000000000000000,表示person中还有未赋值

总结:

  • 大部分内存都是固定以内存块进行读取
  • 尽管我们在内存中采用内存对齐形式, 但是系统会自动对属性进行重排, 以此来优化内存

相关文章

网友评论

      本文标题:IOS底层(六): alloc相关: 内存对齐

      本文链接:https://www.haomeiwen.com/subject/wquzcltx.html