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