一、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流程图:
























![[桜井宁宁]COS和泉纱雾超可爱写真福利集-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/4d3cf227a85d7e79f5d6b4efb6bde3e8.jpg)

![[桜井宁宁] 爆乳奶牛少女cos写真-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/d40483e126fcf567894e89c65eaca655.jpg)