1-IOS内存结构

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

一、概述

本文先从源码角度分析了runtime中的object,以及内存结构。然后从RetainCount方面介绍了如何进行管理内存,以及用autoreleasepool自动管理内存的原理,又分析了weak在内存管理的作用和原理。

二、深入runtime中的object

2.1 关于isa指针

所有继承于NSObject的对象有isa指针,其语意就是"is a",是isa指针指向的实例。在objc-private.h文件中objc_object结构体(objc-object.h文件实现)就标明了isa_t,如图2.1。所有继承自 NSObject 的类实例化后的对象都会包含一个类型为 isa_t 的结构体。
在这里插入图片描述
不只是实例会包含一个 isa 结构体,在objc-runtime-new.h文件中有个名为 objc_class 的结构体,它继承于objc_object,所以所有的类也有这么一个 isa,Class就是它的指针类型,如图2.2所示。
在这里插入图片描述
在这里插入图片描述

2.1.1 为什么需要isa指针?

  1. 语义上表示"is a",对象是什么。
  2. 因为在 Objective-C 中,对象的方法并没有存储于对象的结构体中(如果每一个对象都保存了自己能执行的方法,那么对内存的占用有极大的影响)。对象->类对象,类对象中存放实例方法。类对象->元类,元类中存放类方法。当方法被调用时,它要通过自己持有的 isa 来查找对应的类,然后在这里的 class_data_bits_t 结构体中查找对应方法的实现。如图2-3诠释了三者之间的关系。
    在这里插入图片描述

2.1.2 isa的结构

一个isa指针占用64位,为了节省空间,每一位都有特殊的含义。在objc-private.h文件和isa.h文件中定义了isa_t共用体
在这里插入图片描述
在这里插入图片描述
在表2-1中,简要介绍了isa_t共用体在__x86_64__环境中,每一位的意义。

字段名所占位数字段说明
nonpointer1表示isa指针是否是个指针
has_assoc1对象含有或者曾经含有关联引用,没有关联引用的可以更快地释放内存
has_cxx_dtor1当前对象是否有 C++ 或者 ObjC 的析构器(destructor)
shiftcls44在为 indexed、 magic 和 has_cxx_dtor 设置之后,我们就要将当前对象对应的类指针存入 isa 结构体中了。
magic60x3b 用于调试器判断当前对象是真的对象还是没有初始化的空间
weakly_referenced1对象是否有ARC 的弱引用
deallocating1对象正在释放内存
has_sidetable_rc1是否有扩展的retainCount用SideTable来存储
extra_rc8extra_rc = 引用计数 + 1

在这里插入图片描述

2.2 结构体objc_class

在objc-runtime-new.h中有objc_class结构体,不管是NSObject的初始化还是方法的被调用,都与之密切相关,objc_class继承objc_object
在这里插入图片描述

  • isa是指向元类的指针。
  • super_class 指向当前类的父类
  • cache用于缓存指针和vtable,加速方法的调用
  • bits就是64位的结构体,指向存储类的方法、属性、遵循的协议等信息的地方

2.2.1 class_data_bits_t 结构体

class_data_bits_t 的结构体,只含有64位的bits,用于存储与类有关的信息,其实就相当于相当于 class_rw_t 指针加上 rr/alloc 的标志(指针+标志位)
在这里插入图片描述
在这里插入图片描述
bits意义是class_rw_t指针加标志位,不同位意义如下
在这里插入图片描述

标志占位数字段说明
isSwift1FAST_IS_SWIFT 用于判断 Swift 类
hasDefaultRR1FAST_HAS_DEFAULT_RR 当前类或者父类含有默认的 retain/release/autorelease/retainCount/_tryRetain/_isDeallocating/retainWeakReference/allowsWeakReference 方法
requiresRawIsa1FAST_REQUIRES_RAW_ISA 当前类的实例需要 raw isa
class_rw_t47是class_rw_t的指针,用于指向真正存储方法、属性、协议的地方。FAST_DATA_MASK就是取data的掩码。

2.2.2 class_rw_t结构体

OBJC类的属性、方法、协议等都保存在class_rw_t中
在这里插入图片描述
其中class_rw_t中的flags成员中比较重要的位域(objc-runtime-new.h)定义如下:
在这里插入图片描述

标志占位数字段说明
RW_REALIZED1类是已经注册的类
RW_FUTURE1类是尚未解析的future class
RW_INITIALIZED1类是已经初始化的类
RW_INITIALIZING1类是正在初始化的类
RW_COPIED_RO1class_rw_t->ro是class_ro_t的堆拷贝,此时类的class_rw_t->ro是可写入的,拷贝之前ro的内存区域锁死不可写入
RW_CONSTRUCTING1类是正在构建而仍未注册的类
RW_CONSTRUCTED1类是已经构建完成并注册的类
RW_LOADED1类是load方法已经调用过的类

2.2.3 class_ro_t结构体

class_ro_t存储了当前类在编译期就已经确定的属性、方法以及遵循的协议,如图2.8所示。
在这里插入图片描述

变量名备注
baseMethodList直接写在Class中的方法列表
baseProtocolsClass直接继承的协议列表
basePropertiesClass直接写的@property
ivars直接写在Class的实例变量
instanceStart本类偏移所有父类的字节数
instanceSize本类所有实例变量大小的和

其中class_ro_t中的flags成员中比较重要的位域(objc-runtime-new.h)定义如下:
在这里插入图片描述

标志占位数字段说明
RO_META1类是元类
RO_ROOT1类是根类
RO_HAS_CXX_STRUCTORS1类有C++构造/析构函数
RO_HAS_LOAD_METHOD1类有实现load方法
RO_HIDDEN1隐藏类
RO_IS_ARC1类使用ARC选项编译
RO_HAS_CXX_DTOR_ONLY1类有C++析构函数,但没有C++构造函数
RO_FORBIDS_ASSOCIATED_OBJECTS1类禁止使用关联对象
RO_FUTURE1类是尚未解析的future class
RO_REALIZED1类是已经注册的类

2.2.4 objc_class加载的真正过程

  • 在编译期间类的结构中的 class_data_bits_t *data 指向的是一个 class_ro_t * 指针。
    在这里插入图片描述
  1. 在runtime期间,执行realizeClassWithoutSwift方法中:
    1. 将结果从 class_rw_t 强制转换为 class_ro_t 指针
    2. 初始化一个 class_rw_t 结构体
    3. 设置结构体 ro 的值以及 flag
    4. 把rw设置成Class的正确data
      在这里插入图片描述
      执行完realizeClassWithoutSwift类所占用内存的布局如图
      在这里插入图片描述
  2. realizeClassWithoutSwift的最后调用methodizeClass。
    1. 将ro中的methods、properties、protocols都加到rw中,
    2. 将本Class的未绑定的Categories的methods、properties、protocols都加到rw中。
      在这里插入图片描述
  • 28
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值