NSObject的本质

clang -rewrite-objc main.m -o main.cpp
NSObject是所有类的基类,所有的类都继承自它,它太平常了,平常到我们从不去多加任何思考,但是它又那么重要,因为他是OC的基础,所以今天我们将通过一下几点对NSObject抽丝剥茧,看看他的底层到底是怎样的:

  • 一个 NSObject 对象占用多少内存?
  • 对象的 isa 指针指向哪里?
  • OC 的类信息存放在哪里?

思考一下:一个 OC 对象在内存中是如何布局的?
我们创建一个简单 Command line 项目,然后通过xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -0 main.cpp命令把 .m 文件转换为 c++文件查看一下底层代码,然后在转换后的.cpp文件中搜索struct NSObject_IMPL {找到:

struct NSObject_IMPL {
    __unsafe_unretained Class isa;
};

这就是NSObject的底层实现,我们也可以直接进入到NSObject.h的头文件中看看NSObject是如何定义的:

@interface NSObject {
    Class isa;
}
@end

可以发现NSObject.h头文件的定义和.cpp文件中都是一样的,NSObject的底层就是一个 C++ 结构体,结构体中只有一个class类型的isa成员.这个class又是什么类型呢?点进去看一下:

typedef struct objc_class *Class;

原来class就是一个指向struct objc_class结构体类型的指针!现在知道了Class是一个指针,而NSObject底层就只有一个Class isa那我们就知道了NSObject占用多少内存了.因为指针在64位系统中占8个字节,在32位系统中占4个字节.所以我么可以猜测:NSObject在内存中占8个字节.我们猜测的正确吗?下面开始验证一下:

NSLog(@"NSObject 占用了 %zd 个字节?", class_getInstanceSize([NSObject class]));
//打印输出
NSObject 占用了 8 个字节?

难道我们的猜测是正确的?
注意:class_getInstanceSize()是获取某一个类创建出来的实例对象所占用的内存大小.
系统中还有一个方法是取出一个指针所指向的内存的大小:malloc_size(<#const void *ptr#>)运行一下代码:

NSObject *obj = [[NSObject alloc]init];
NSLog(@"NSObject 占用了 %zd 个字节?", class_getInstanceSize([NSObject class]));
NSLog(@"obj指针指向的内存占用了 %zd 个字节?",malloc_size((__bridge const void *)obj));

// 打印
NSObject 占用了 8 个字节?
obj指针指向的内存占用了 16 个字节?

好了,现在有两个结果:8 和 16.哪一个才一个 NSObject 对象占用多少内存?的结果呢?答案是16个字节.因为class_getInstanceSize ()返回的其实并不是一个对象的全部内存大小,实际上它返回的是一个类的实例对象的成员变量所占用的内存大小,我们可以通过 runtime 的源码看一下:
查看步骤:

  1. 打开 runtime 源码搜索class_getInstanceSize
  2. 找到
size_t class_getInstanceSize(Class cls)
{
    if (!cls) return 0;
    return cls->alignedInstanceSize();
}
  1. 点击进入alignedInstanceSize:
    // Class's ivar size rounded up to a pointer-size boundary.
翻译:返回的是class的ivar大小
    uint32_t alignedInstanceSize() {
        return word_align(unalignedInstanceSize());
    }

可以看到, class_getInstanceSize()的确返回的是实例对象的成员变量锁占用的大小.其实 class_getInstanceSizemalloc_size的关系就好比下图:

2258226-e13d60b61ed62192.png

所以正确的说法应该是:

一个 NSObject 对象占用多少内存❓
系统分配了 16 个字节给NSObject对象(通过 malloc_size可获得),但NSObject对象内部只是用了 8 个字节的空间(在64位环境下可通过class_getInstanceSize函数获得).

猜你喜欢

转载自blog.csdn.net/weixin_34273479/article/details/86922877