一个NSObject占用多少内存?
NSObject *obj = [[NSObject alloc] init];
答:系统分配了16字节,但NSObject只使用了8个字节
由果索引去探求类的本质
- 我们知道OC会被编译器翻译成C/C++,进而翻译成汇编,最终翻译成机器语言。
- 在命令行将
.m
文件转换成.cpp
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc OC源文件 -o 输出的cpp文件
- 打开
cpp
文件后发现类的本质其实就是一个结构体
struct NSObject_IMPL {
Class isa;
};
- 在进入Class的头文件会发现,其实clas就是指向结构体的指针
typedef struct objc_class *Class;
到这为止,可以初步认为NSObject在64位的环境下占8个字节
,在32环境上占4个字节
因为结构体里面就一个isa
成员,结构体的地址就是 isa
的地址,这个地址占用的内存大小就是结构体的大小,即isa
的大小
占用内存和分配内存一样吗?
- 使用runtime的
class_getInstanceSize
方法,输出大小为8
NSObject *obj = [[NSObject alloc] init];
// 输出为8
NSLog(@"class_getInstanceSize--%zd", class_getInstanceSize([NSObject class]));
- 使用malloc,输出大小为16
NSObject *obj = [[NSObject alloc] init];
// 输出16
NSLog(@"malloc_size--%zd", malloc_size((__bridge const void *)obj));
- 查看runtime源码继续探究原因
-
下载数字较大的文件,数字越大表示代码越新
- 搜索
class_getInstanceSize
- 点进去查看内部实现
// Class's ivar size rounded up to a pointer-size boundary.
uint32_t alignedInstanceSize() {
return word_align(unalignedInstanceSize());
}
通过注释发现其实返回的是Class's ivar size
,而NSObject
对象只有一个isa
成员变量,所以返回的是8个字节
- 而
alloc
实质上是调用allocWithZone
,同理通过查看源码的方式找到_objc_rootAllocWithZone
,通过其找到class_createInstance(cls, 0)
进入到最终的函数为
size_t instanceSize(size_t extraBytes) {
size_t size = alignedInstanceSize() + extraBytes;
// CF requires all objects be at least 16 bytes.
if (size < 16) size = 16;
return size;
}
至此,所有的谜团都解开了
CF
要求至少得返回16个字节的内存大小,所以即便NSObject只占用了8个字节,系统也会按照最小的要求返回16个字节。
最终的答案
一个NSObject占用多少内存?
1、通过malloc_size函数得知系统分配了16个字节给NSObject对象
2、通过class_getInstanceSize函数得知,NSObject对象内部只使用了8个字节空间(在64bit环境下)
总结
通过问题,一步一步推倒,一步一步深挖,这个过程就好像寻宝一样,最终揭开了问题的真相。由此得知,很多事情不能浮于表面,通过本质去看问题会看到很多不一样的东西。