【MJ-iOS底层原理总结】一个NSObject对象占用多少内存?

1,182 阅读1分钟
1. 在编译器中查看,有两种查看Size的方法
  1. 方式一:class_getInstanceSize([NSObject class])
  2. 方式二:malloc_size((__bridge const void *)(obj))
  3. 编译器中运行结果如下: image.png
    • 发现class_getInstanceSizemalloc_size方法得到的结果不一样。
2. 那究竟哪个才是NSObject实际占用内存的大小呢?
  1. 查看OC源码一探究竟
    • 登陆苹果开源网站:opensource.apple.com/tarballs/ ,搜索objc

    • 找到最新的OC源码(数字最大的): image.png

    • 下载并打开项目,在OC源码项目中搜索class_getInstanceSize,找到了其实现: image.png

    • 继续往下查看,发现该方法的注释: image.png

    • 大致意思为:返回了这个类中的成员变量所占用的大小。

  2. 总结:
    • class_getInstanceSize([NSObject class])的意思是:获得NSObject实例对象的成员变量所占用的大小 ,并非获取NSObject所占用的大小。
    • malloc_size((__bridge const void *)(obj))的意思是:获得obj指针所指向内存的大小。
    • 结论:所以一个NSObject对象占用16个字节,而真正利用起来的只有8个字节。如下图所示: image.png
3. 为什么会这样呢?
  1. 还是从源码中找线索,寻找alloc的源码,为了缩小搜索范围,我们知道alloc的本质是allocWithZone,所以我们在源码中搜索allocWithZone。找到NSObject.mm文件中的方法: image.png
  2. 继续往下搜索_objc_rootAllocWithZone image.png
  3. 再往下搜索_class_createInstanceFromZone,发现了底层调用了calloc方法,并指定了一个size,这个size是通过instanceSize()方法获取的 image.png
  4. 搜索instanceSize(,终于发现了真相: image.png if (size < 16) size = 16;,原来底层判断了一个对象至少需要分配16个字节,如果小于16则强制分配16字节给这个对象。
  5. 这样我们就可以理解,为什么NSObject对象只有一个isa成员变量,只占用了8个字节,但为什么NSObject对象确会占用16字节了。
4. 总结:
  • 系统分配了16个字节给NSObject对象(通过malloc_size函数获得)
  • 但NSObject对象内部只使用了8个字节的空间(64bit环境下,可以通过class_getInstanceSize函数获得)
5. 补充:用Xcode调试模式,窥探NSObject的内存
  1. 进入断点模式 image.png
  2. 进入Debug->Debug Workflow->View Memory模式 image.png
  3. 将obj的地址,放入Address中,回车进行查看: image.png
  4. 我们可以发现,后8个字节全是0,说明其中并没有存放东西,所以也印证了我们之前的结论。