对象内存和isa,class_ro_t,class_rw_t
1.一个NSObject对象占用多少内存?
Objective-C的面相对象都是基于C/C++的数据结构中的结构体实现的,
OC 代码转成C++ ,但是如果是IOS工程则需要其他的命令 ---->移步https://www.jianshu.com/p/41341732291e
clang -rewrite-objc main.m -o main.cppxcrun -sdk iphoneos clang arch arm64 -rewrite-objc main.m -o main-arm64.cpp
转成指定架构的cpp代码
->一个OC对象在内存红如何布局?
OC的实现 转成C++之后的实现typedef struct objc_class *Class;Class 是结构体
图解>系统分配了16个字节给NSObject对象(通过malloc_size 函数获得)
>但是NSObject对象内部只使用了8个字节的空间(64bit环境下,可以通过class_getInstanceSize 函数获得)
注意:容易混淆的两个函数
创建一个实例对象,至少需要多少内存?
#import <objc/runtime.h>
class_getInstanceSize([student class])
创建一个实例对象,实际上分配了多少内存?
#import <malloc/malloc.h>
malloc_size((__bridge const void *)obj)
sizeof(),在编译的时候就能确定其大小
1.2Object-C中的对象,主要可以分为3种
instance对象(实例对象),是通过alloc出来的对象,每次调用alloc都会产生新的instance对象
NSObject *object1 = [[NSObject alloc] init];
NSObject *object2 = [[NSObject alloc] init];
上面是两个不同的对象,分别占用不同的内存
instance 对象在内存中存储的信息包括
isa指针
其他成员变量
class 对象(类对象)
objectClass1-objectClass5都是NSObject的class对象(类对象)class 对象在内存中存储的信息主要包括
isa指针
superclass指针
类的属性信息(@peoperty),类的对象方法信息(instance method),类的协议信息(protocol),类的成员变量信息(ivar)
meta-class对象(元类对象)
Class objectMetaClass = object_getClass([NSObject class]);可以获取元类对象
每个类在内存中有且只有一个meta-class对象
metal-class对象和class对象的内存结构是一样的,但是用途不一样,在内存中存储的信息包括
isa指针,superclass指针,类的类方法信息..........
各个方法的具体返回值情况
Student对象的源码信息 继承之后的源码结构1.Class objc_getClass(const char *aClassName)
1> 传入字符串类名
2> 返回对应的类对象
2.Class object_getClass(id obj)
1> 传入的obj可能是instance对象、class对象、meta-class对象
2> 返回值
a) 如果是instance对象,返回class对象
b) 如果是class对象,返回meta-class对象
c) 如果是meta-class对象,返回NSObject(基类)的meta-class对象
3.- (Class)class、+ (Class)class
1> 返回的就是类对象
- (Class) {
return self->isa;
}
+ (Class) {
return self;
}
2.对象isa指针指向哪里?
isa指针 class对象的superclass指针 meta-class对象的superclass指针instance 对象的isa指向class对象
class对象的isa指向meta-class对象
meta-class对象的isa指向基类的meta-class对象
在arm64架构之前,isa就是一个普通的指针,存储着Class,Meta-Class对象的内存地址
从arm64架构开始,对isa进行优化,变成一种共用体()结构,还使用位域啦哎存储更多的信息
isa(arm64)uintptr_t nonpointer : 1;0代表普通指针,存储祝贺Class,Meta-Class对象的你内存地址,1代表优化过的,使用位域存储着更多的信息
uintptr_t has_assoc : 1; 是否有设置过关联对象,如果没有,释放时会更快
uintptr_t has_cxx_dtor : 1; 是否有C++的析构函数(.cxx_destruct),如果没有,释放时会更快
uintptr_t shiftcls : 33; 存储着Class,Meta-Class对象的内存地址信息
uintptr_t magic : 6;用于在调试时分辨对像是否未完成初始化
uintptr_t weakly_referenced : 1;是否有被弱引用指向过,如果没有,释放时会更快
uintptr_t deallocating : 1; 对象是否正在释放
uintptr_t has_sidetable_rc : 1;引用计数器是否过大,无法存储在isa中,如果为1,那么引用计数会存储在一个叫SideTable的类的属性中
uintptr_t extra_rc : 19;里面存储的值是引用计数器减1
---
---
isa,superclass总结3.OC的类信息存放在哪里
对象方法,属性,成员变量,协议信息,存储在class对象中
类方法,存放在meta-class对象中
成员变量的具体指存放在instance对象
4.类继承之后转成C++的代码
student类
student3继承student
student转成C++之后的代码,本质是结构体
student3转成C++之后的代码,其中包含指向父类的结构体指针
5.class_ro_t和class_rw_t
objc_class的相关结构(精简版)class_ro_t 存储了当前类再编译期就已经过确定的属性,方法以及遵循的协议,里面是没有分类的方法的,那些运行时添加的方法将会存储在运行时生成的class_rw_t中(ro即表示read only是无法进行修改更改的)
objc类中的属性,方法还有遵循的协议等信息都保存在class_rw_t中,其中
method_array_t methods;//方法列表(类对象存放对象方法,元类对象存放类方法)
property_array_t properties;//属性列表
protocol_array_t protocols;//协议列表
上面三个都是二维数组,是可读可写的,包含了类的初始内容,分类的呢内容,methods 中存储method_list_t ----> method_t
二维数组,method_list_t ----> method_t,这三个二维数组中的数据有一部分是从class_ro_t中合并过来的
->class_rw_t的生成时机
类的realizeClass运行之前 类的realizeClass运行之后class_rw_t生成在运行时,在编译期间,class_ro_t结构体就已经确定过,objc_class中的bits的data部分存放着该结构体的地址,在runtime运行之后,具体来说是运行runtime的relizeClass方法时,会生成class_rw_t结构体,该结构体包含了class_ro_t,并且更新data部分,换成class_rw_t结构体的地址
两个结构体的成员变量有很多相同的地方,他们都存放着当前类的属性,实例变量,方法,协议等
区别:class_ro_t存放的是编译期间就确定的,而class_rw_t是在runtime时才确定的,他会先将class_ro_t的内容拷贝过去,然后再将当前类的分类的这些属性,方法等拷贝到其中高,所以可以说class_rw_t是class_ro_t的超集,实际访问类的方法,属性等也都是访问class_rw_t中的内容