前言
今天探索的是对象的底层实现,创建对象就要使用到alloc,那么alloc在底层做了什么造就了一个对象?
我们先来看一个小例子:
这里三个打印分别是:对象本身, 对象内存 , 指向对象的指针的地址,我们知道&p1 &p2 &p3 是在栈空间上,且栈是连续的(因为指针占用8字节,所以它们之间相差8字节)
,它们都指向了同一个内存地址。
如下图所示:
接下来就一起探索下,alloc是如何开辟内存空间的?init又做了什么,p2 p3对象的内存地址和p1 是一样的?
准备工作
- 由于我们平常使用的环境是没有办法探索到底层的实现的,所以这里我们需要下载一份
objc4-818可编译源码的源码。
源码编译配置:
①. 选择你所创建的 targets
②. enable hardened runtime -> NO
③. build phase -> denpendenice -> objc
④. team 选择 None
- 掌握
断点有助于底层探索,这里奉上连接
探索:
通过断点的方式探索到了alloc底层使用libobjc.A.dylib库的objc_alloc方法,如下图:
Step into instruction(hold Control) 按住Control 进入用户说明
打开libobjc.A.dylib库,接下来分析alloc源码,首先通过汇编跟流程来到了objc_alloc方法,打下断点(再次强调,这里的断点并不是一直Enable,只有当断点断在外部我们研究的对象身上时,再把内部断点Enable,保证我们研究方向不会跑偏。)
在callAlloc出现了分支,走的是objc_msgSend(DXJPerson, @selector(alloc)) 等同于[DXJPerson alloc](为什么会有这一步呢?)
紧接着内部调用alloc
这里我们发现又调回了callAlloc
这次走的是_objc_rootAllocWithZone(cls,nil) (这里留个问题:objc_msgSend(DXJPerson, @selector(alloc)) 内部必然做了什么影响到了 cls->ISA()->hanCustomAWZ()的值)
来到_objc_rootAllocWithZone
alloc核心实现了
注释给到了这个方法主要目的是class_createInstance 通过class创建一个实例对象,那么这个对象必然是要丢出去给外部使用的,我们便清楚的定位到了要研究对象return obj,这个obj是怎么生成的呢?影响obj的参数有哪些?
- 计算开辟内存空间大小
- 开辟空间
obj和cls通过isa进行关联
1. obj 开辟内存空间大小
cls->instanceSize 计算对象所占的内存空间大小
计算类的内存大小有两种方式
- 红框标注:编译器快速计算内存大小;以16字节对齐(16的倍数);现在使用的方式
- 绿框标注:8字节对齐(8的倍数);以前使用的方式
分别看下代码实现:
方式一绿框标注:8字节对齐(8的倍数)
影响类的内存大小:类成员变量(类本身的成员变量;继承自父类的成员变量; isa)
WORD_MASK = 7
8字节对齐算法分析
eg: x = 10 则
(x + WORD_MASK) & ~WORD_MASK => (10 + 8 ) & ~7 => 18 & ~7
0001 0100 18
& 1111 1000 ~7
= 0001 0000 16
方式二(红框标注):编译器快速计算内存大小;以16字节对齐(16的倍数);
fastpath() 将最有可能的执行的分支告诉编译器,基本上行都支持cache.hasFastInstanceSize()快速计算内存大小
16字节对齐算法分析(和8字节相同)
eg: x = 24 则
(x + size_t(15)) & ~size_t(15) => 39 & ~15
0010 0111 39
& 1111 0000 ~15
= 0010 0000 32
x= 16 16 + 15 = 31
0001 1111
& 1111 0000
= 0001 0000 = 16
现在是16字节对齐操作,也就是说,一个对象所占用的内存大小是至少16字节。为什么是16字节对齐呢?
- 一个对象,必然会有一个属性,继承自
NSObject类的Class isa(objc_class *Class)所以Class结构体指针,占8个字节,若无其他属性时,16字节对齐则会给该对象预留出8字节来,如果是8字节对齐没有预留出来8字节,相当于当前对象的isa紧挨着下一个对象的isa,会容易造成访问混乱。 - 16字节对齐后,方便
CPU读取速度,以空间换时间,访问也更安全,不会产生访问混乱的问题。
2. 开辟内存空间
3. obj和cls通过isa进行关联
总结:
alloc流程图