一个NSObject对象的大小
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import <malloc/malloc.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSObject *obj = [[NSObject alloc] init];
NSLog(@"size %zd", class_getInstanceSize([NSObject class]));
NSLog(@"malloc出的大小 %zd", malloc_size((__bridge const void *) obj));
}
return 0;
}
输出结果如下:
class_getInstanceSize并不为一个对象所分配的内存空间,实质为调用该方法
通过OC源码可以发现CoreFoundation对一个对象的大小做了硬性规定,如下图所示:
通过对OC文件进行编译得到的C++文件找到对象本质是一个包含Class类型isa的结构体,如下图所示:
Class是一个指向结构体的指针,如下两张图所示
创建一个Person对象,里面添加两个成员变量,编译得到对应的C++文件结构如下图所示:
进一步复杂一下实例对象添加一个属性,编译后会得到如下结构:
属性会生成一个成员变量,但是get set方法不会出现在实例方法中,实例可能会有多个,所以实例方法会存在类对象中,isa指向当前类的类对象具体如图所示:
此时我们会发现isa指向的地址和当前类的类对象并不是一个地址,这是由于iOS在arm64架构之后增加了ISA_MASK,需要进行一步位运算,我们可在OC的源码中找到
由于我创建的是命令行项目,而且Mac还不是M1芯片,所以需要使用x86的ISA_MASK
通过位运算得出isa确实是指向当前类的类对象。
接下来验证类对象的isa是否指向元类对象
由于Class类型并没有把isa开放,所以只能自己编写一个Class结构体,可以参考OC源码进行一个简单的编写
可以看到Class的声明是这样的
通过源码可找到objc_class最新的实现是这样的
通过上面三张图基本可以确定类对象包含方法列表、属性信息、协议信息
通过objc_object可以找到isa
为了验证isa和superclass的指向,于是就编写了如下结构的obj_class
桥接之后解决报错,最后得出类对象isa指向元类对象,但是没有发现ISA_MASK的参与,不知道是不是由于是自己写的结构体所以没有ISA_MASK,欢迎大佬们指教。
接下来测试superclass,上图
可以很清晰的看到obj_class的superclass的指向,最后我们可以得出网上非常流行的这张指向顺序的图
通过本文对对象结构的探索,可以得出如下的对象信息结构图