OC底层原理之NSObject

本系列主要是看完MJ的OC底层原理课程所写的总结,希望自己能加深对iOS底层的了解。

NSObject的本质

NSObject的底层实现就是一个结构体 ,而且只带有一个Class类型的成员变量isa

@interface NSObject{
    Class isa;
}

struct NSObject_IMPL{
    Class isa;
}
复制代码

OC对象的本质

分析Object的内存分布

  • 首先科普

    1 位(bit): 计算机中最小的存储单位,只能存储0或者1。

    1 字节(b):8位(bit)。 就是byte,同计算机语言(例如Java、PHP等)中的byte是一回事儿。

    1 kb: 1024 个字节。

    1 mb: 1024 kb

    1 gb: 1024 mb

    1 tb: 1024 gb

    1 pb: 1024 tb

  • NSObject占用的内存?

    • 在使用calloc为对象分配一块内存空间之前,先要获取对象在内存的大小:

      size_t instanceSize(size_t extraBytes) {
          size_t size = alignedInstanceSize() + extraBytes;
          if (size < 16) size = 16;
          return size;
      }
      复制代码
      • 这里是objc获取分配内存大小的源码可以看出object小于16的时候,会强制赋值16,也就是说系统规定NSObject最小的size是16

      这里是libmalloc的源码,定义了NSObject最大分配内容的大小,从注释可以看出系统分配内存大小都是16的倍数。

      • 这样分配的目的是为了更快的分配内存

      • 这里还有个内存字节对齐的问题

    • NSObject对象内部只使用了8个字节的空间

      • 由于NSObject内部只有一个isa指针的成员变量,而指针所占的内存就是8个字节
    • class_getInstanceSize和malloc_size

      class_getInstanceSize: Returns the size of instances of a class.

      The malloc_size() function returns the size of the memory block that backs the allocation pointed to by ptr.  The memory block size is always at least as large as the allocation it backs, and may be larger.
      复制代码
      • class_getInstanceSize代表的是实例对象的成员变量所占用的大小
      • malloc_size代表的是obj指针所指向堆空间的大小
          NSObject *obj = [[NSObject alloc] init]
      	NSLog(@"%zd",class_getInstanceSize([NSObject class])) //8
         	NSLog(@"%zd",malloc_size((__brdge const void *)obj)) //16
      复制代码
    • class_getInstanceSize和sizeOf

      • sizeOf在编译时决定类的大小
      • class_getInstanceSize在运行时 决定类的大小

    内存字节对齐

    sturct SturctOne{
        char a // 1
        double b // 8
        double c // 8
    }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 
    复制代码

    这个问题就是内存字节对齐导致的

    每个特定平台上的编译器都有自己的默认对齐参数。可以通过预编译命令 #pragma pack(n),n=1,2,4,8来改变这一系数.(一些旧版Xcode只支持结构体定义后加上 _ attribute_ ((aligned (n)))的方式)

    Xcode 中默认为__#pragma pack(8)__。如果在代码执行前加一句#pragma pack(1) 时就代表不进行内存对齐,上述代码打印的结果就都为 15。

    sturct SturctOne{
        char a // 1
        double b // 8
        double c // 8
    }MyStruct1
    NSLog(@"%lu", sizeof(MyStruct1));
    #pragma pack(n) n = 1 //17
    #pragma pack(n) n = 2 //18
    #pragma pack(n) n = 4 //20
    #pragma pack(n) n = 8 //24
    复制代码

    为什么需要内存对齐

  • 减少CPU读取数据的次数提高,从而提高程序效率

    • 从上面的例子分析,假设CPU一次能取8个字节的数据, 第一次从地址0开始取,一次就取到a的数据,而要取b的数据要从地址0读取数据的一部分,然后再从地址7开始读取数据的另外一部分,要读取两次数据。

转载于:https://juejin.im/post/5c8e183b6fb9a0710b725bd6

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值