一、alloc的作用
作为oc语言开发者,大家都知道如何创建一个实例对象,没错就是alloc。那么alloc在底层是如何调用的呢?我们一起来探究一下。
代码搞起
LGPersion *p = [LGPersion alloc];
LGPersion *p1 = [p init];
LGPersion *p2 = [p init];
NSLog(@"p : %@---%p----%p",p,p,&p);
NSLog(@"p1: %@---%p----%p",p1,p1,&p1);
NSLog(@"p2: %@---%p----%p",p2,p2,&p2);
复制代码
打印结果
p : <LGPersion: 0x6000006c0160>---0x6000006c0160----0x7ffee9ae3c58
p1: <LGPersion: 0x6000006c0160>---0x6000006c0160----0x7ffee9ae3c50
p2: <LGPersion: 0x6000006c0160>---0x6000006c0160----0x7ffee9ae3c48
复制代码
通过上述代码和打印结果可以明显看出:p,p1,p2三者的对象地址是一样的,但是指针地址不一样,所以p,p1,p2三个对象指向的是同一个内存空间,在内存中的表现如图所示:
结论:alloc开辟了对象的内存空间,init并没有对空间有操作
二、探究alloc的方法
然而alloc是如何开辟内存的呢?我们该如何去探究呢?接下来我们用3种方法去探索:
1、setp into + 符号断点
先在alloc之前加个断点,然后按住control
点击setp into
进入
然后加入符号断点objc_alloc
放开断点进入libobjc.A.dylib objc_alloc:
2、汇编
汇编模式:debug
-> debug Workflow
->Always Show Disassembly
具体使用:进入断点后按照上述步骤即可进入汇编代码。如图:
1、断点
2、进入汇编
汇编:
3、step into
按住control
点击step into
进入alloc
3、直接符号断点
我们都知道这个方法是alloc
所以直接下符号断点,流程如下:
先在alloc
前打断点断点之后如图
加入符号之后直接放开当前断点
然后如图所示
三、alloc源码跟踪
打开Source Browser 搜索objc
,如图:
下载objc4-818.2.tar.gz
解压
command + 左键alloc
直接跳转到
继续 command
继续
进入_objc_rootAllocWithZone
继续进入_class_createInstanceFromZone
(核心代码)
如图所示(已经标出主要部分)
cls->instanceSize(extraBytes)
计算大小
calloc(1, size)
开辟空间
initInstanceIsa(cls, hasCxxDtor)
将开辟的空间跟类关联起来
细细一品确实是核心东西 ,那么下面开始挨个探究。
1、计算大小
我们首先进入instanceSize
如图
有个判断先,这里判是否有缓存 有的话直接获取返回(节省时间)
进入cache.fastInstanceSize
command 查看FAST_CACHE_ALLOC_MASK
值为0x1ff8
如图点断所示,我们需要进入align16
梳理一下这个算式
设x = 9
则算式为 (9 + 15) & ~ 15
二进制计算
x = 0000 1001
15 : 0000 1111
9 + 15 : 0001 1000
~15 :1111 0000
9 + 15) & ~ 15 : 0001 0000 结果为16
设x = 17
则算式为 (17 + 15) & ~ 15
二进制计算
x = 0001 1000
15 : 0000 1111
9 + 15 : 0010 0111
~15 :1111 0000
9 + 15) & ~ 15 : 0010 0000 32
复制代码
所以 align16
是一个对齐方法,即返回16
的整数倍,如果不足16
,返回16
,如果x>16*n && x<16 * (n + 1)
则返回 16*(n +1)
,等同于>> 4 <<4
,该方法叫做字节对齐,字节对齐的意义是什么?
提高cpu读取速度:以固定的长度读取数据,会大幅度提高cup工作效率
接下来查看 普通方法 command 进入alignedInstanceSize
继续进入unalignedInstanceSize
(没有对齐的InstanceSize
)
所以此方法返回的是对象的大小(未对齐之前的),那么对象的大小如何判断的呢?我们细想一下,对象里面有什么?属性、方法、和协议等;但是对象的大小只取决于成员变量。该方法返回的是data
中的ro
的 instanceSize
,即实例变量的大小。该方法的注释中也提到 May be unaligned depending on class's ivars.
成员变量的大小。
然后 word_align
WORD_MASK
为7
所以该方法是8字节对齐方法。
最后返回到 instanceSize
中返回
2、开辟空间
此图断点为刚声明,虽然有地址,却是脏地址,不可用的。
越过开辟的方法,之后发现地址变了,但是po一下obj
发现只是一个地址,跟平时的对象不太一样
因为接下来的步骤还没走,class
绑定
3、绑定
进入 initInstanceIsa
进入 initIsa
完事了,我们回到 _class_createInstanceFromZone
并po,发现obj正常了,跟平时的一样,说明我的alloc走完了。
4、总结
通过以上的探索在下绘制了,简单的alloc流程图: