对象内存和isa,class_ro_t,class_rw_t

2021-02-25  本文已影响0人  牛奶红茶

1.一个NSObject对象占用多少内存?

Objective-C的面相对象都是基于C/C++的数据结构中的结构体实现的,

OC 代码转成C++ ,但是如果是IOS工程则需要其他的命令 ---->移步https://www.jianshu.com/p/41341732291e

clang -rewrite-objc main.m -o main.cpp

xcrun -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指针,类的类方法信息..........

各个方法的具体返回值情况

 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;
 }

Student对象的源码信息 继承之后的源码结构

2.对象isa指针指向哪里?

instance 对象的isa指向class对象

class对象的isa指向meta-class对象

meta-class对象的isa指向基类的meta-class对象

isa指针 class对象的superclass指针 meta-class对象的superclass指针

在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的生成时机

class_rw_t生成在运行时,在编译期间,class_ro_t结构体就已经确定过,objc_class中的bits的data部分存放着该结构体的地址,在runtime运行之后,具体来说是运行runtime的relizeClass方法时,会生成class_rw_t结构体,该结构体包含了class_ro_t,并且更新data部分,换成class_rw_t结构体的地址

类的realizeClass运行之前 类的realizeClass运行之后

两个结构体的成员变量有很多相同的地方,他们都存放着当前类的属性,实例变量,方法,协议等

区别:class_ro_t存放的是编译期间就确定的,而class_rw_t是在runtime时才确定的,他会先将class_ro_t的内容拷贝过去,然后再将当前类的分类的这些属性,方法等拷贝到其中高,所以可以说class_rw_t是class_ro_t的超集,实际访问类的方法,属性等也都是访问class_rw_t中的内容

上一篇下一篇

猜你喜欢

热点阅读