在上篇文章咱们评论了目标的创立进程,以及目标的内存拓荒、内存对齐规矩,接下来咱们来持续研究目标的内存,本文将从一下几个方面来打开
1. 影响目标内存的因素
2. 目标的内存剖析
3. 联合体和位域
4、nonPointerisa
5、怎么利用isa的位运算得到类目标
6、new办法
一、影响目标内存的因素
首先咱们仍是在我咱们的LSPerson里边增加一下特点和办法:
咱们按照 上一篇文章内存对齐规矩(目标内部以8字节对齐,体系实践分类内存以16字节对齐
)知道 目标内部需求 40个字节(包含了特点+isa指针,实践38,可是8字节对齐所以40), 体系实践拓荒48个字节(16字节对齐所以最小是48),咱们经过体系供给的办法验证一下
咱们在上一篇文章中struct结构体核算中发现,成员的方位会影响结构体内存的巨细,可是在目标中咱们发现
如同并没有(能够经过调整特点次序来验证)因为方位不同,影响目标拓荒的内存巨细,是因为体系对特点进行了
重排,到达内存优化
一起还得出一个定论:体系实践分配给目标的内存巨细不仅和类目标中增加的办法无关,一起也与成员变量(特点)的次序无关
。
留意:
咱们上面验证了目标的拓荒内存巨细跟特点问题是没有关系的,那么成员变量了也是相同吗?
定论:经过上面的几段段吗咱们能够发现,体系并不会对实例变量进行重排
。
二、目标的内存剖析
在上面咱们说体系会对特点进行重排,那么咱们看一下体系是怎么摆放的,咱们经过LLDB进行调试 输入 x/6gx
留意:咱们经过x/6gx 得到目标的内存地址,经过剖析咱们发现age+number被体系重排之后放在一一个内存块里边。而且
目标里边地址存储的是值。
经过上面咱们知道:iOS目标的内存巨细和特点以及特点的赋值次序无关,体系会自动重排目标特点的次序,来进行内存优化,而且目标里边存储的是特点值。目标里边存储的是特点值,并不是特点。
三、位域和联合体
1、什么是位域
位域声明:有些信息在存储是,并不需求占用一个完整的字节,而只需求占几个或一个二进制位
。例如在存放一个开关变量时,只要0和1两种状况,用1位二进制位即可。为了节约存储空间,并使处理简洁,C言语又供给了一种数据结构,称为“位域”或“位段”。(比如char类型的需求1个字节,也便是8位,假如咱们存储的是一个开关变量,也有0和1,这个是用8位就会浪费,为了节约空间咱们就能够运用1位二进制表明来节约存储空间)
所谓“位域”是把一个字节中的二进制位划分为几个不同的区域,并阐明每个区域的位数。每一个域有一个域名,答应在程序中按域名进行操作。这样就能够把几个不同的目标用一个字节的二进制位域来表明。
一般在开发中咱们不会这么去运用,只要体系级别的才会去这么操作。
2、什么是联合体(union)
共用体是一种特别的数据类型,答应您在相同的内存方位存储不同的数据类型。您能够界说一个带有多成员的共用体,可是任何时候只能有一个成员带有值。共用体供给了一种运用相同的内存方位的有用办法。
经过上面咱们发现 union里边 目标是互斥的,也便是同一时间里边只会有一个成员带有值。那么联合体的作用是啥了?
因为联合体是互斥的,所以能够节约内存空间
,联合体有必要要能肉包容最大的成员变量,核算出来的巨细有必要是其最大成员变量(基本数据类型)的整数倍。
结构体和联合体的差异:
结构体:成员变量的值能够共存,内存拓荒有必要粗豪
联合体:成员变量的值互斥, 节约内存空间
四、nonPointerisa
在上一遍文章iOS目标的底层探索(上)中咱们经过objc源码剖析了_class_createInstanceFromZone函数知道了目标所需求的内存巨细怎么核算,以及体系拓荒目标内存巨细的规矩,然后在这个办法返回了ojb,也便是咱们需求的实例目标。咱们持续剖析两者是怎么联上的。
经过上面的断点,咱们知道执行了办法initInstanceIsa(或许initIsa)
之后,obj就和LSPerson类进行绑定了。咱们持续看一下这个函数
这个函数里边有一个isa_t
的isa,最终isa = newisa
, 经过源码知道 isa_t 是一个联合体。isa指针是一个class类型的结构体指针,主要用来存储内存地址。isa指针有8个字节即64位。以前版本均为Class类型的结构体指针,而当时遍及运用nonPointerIsa,为了兼容性所有isa_t 采用联合体类型(这也是联合体的优势).
五、怎么用isa的位运算得到类目标
当时都是nonPointerIsa
, isa指针存储的内容保存到了名为ISA_BITFIELD
的结构体中,代码截图如下:
NONPOINTER_ISA 存储的内容
1、nonpointer: 表明是否对isa指针敞开指针优化,0:纯isa指针,1:不止是类目标地址,isa包含了类信息、
目标的引证记数。
2、has_assoc: 相关目标标志位,0没有,1存在。
3、has_cxx_dtor: 该目标是否有C++或许Objc的析构器,假如有析构函数,则需求做析构逻辑,假如没有,
则能够更快的开释目标。
4、shiftcls: 存储类指针的值。敞开指针优化的情况下,在arm64架构中(真机)由33位用来存储类指针。
5、magic: 用户调试器判别当时目标是真的目标仍是没有初始化的空间
6、weakly_referenced: 标志目标是否被指向或许曾指向一个ARC的弱变量,没有弱引证的目标能够更快开释。
7、deallocationg: 标志目标是否正在开释内存。
8、has_sidetable_rc: 当目标引证计数extra_rc所能存储的最大范围时,则需求借用该变量存储进位。
9、extra_rc: 当表明该目标的引证计数值,当目标的引证计数超过最大的存储范围时,则需求运用到上面的
has_sidetable_rc.
在M1架构中,将isa指针内存地址右移3位(清除低3位),左移12位,再右移9位,得到的内存地址即为类目标的内存地址
,如下:
扩展也能够经过 & ISA_MASK 来得到类目标的地址
六、new办法
经过源码剖析,发现和alloc相同也是会之行callAlloc 和init办法