”一个NSObject占用多少内存?“引发的思考

一个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源码继续探究原因
  • 下载数字较大的文件,数字越大表示代码越新


    image
  • 搜索class_getInstanceSize
    image
  • 点进去查看内部实现
// 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环境下)

总结

通过问题,一步一步推倒,一步一步深挖,这个过程就好像寻宝一样,最终揭开了问题的真相。由此得知,很多事情不能浮于表面,通过本质去看问题会看到很多不一样的东西。

你可能感兴趣的:(”一个NSObject占用多少内存?“引发的思考)