一、调试方法
当我们调试时候不知道一个系统方法后面干了些啥,调用了哪些动态库的时候,我们可以通过下断点方式进行调试,有三种方式
1、断点调试
在调用系统方法前加一个断点,例如alloc方法,然后按住control键,点击in键,也就是

这个键,一步一步跳转就能看到该方法调用的顺序,例如

就能知道alloc调用了objc_alloc方法
2、下符号断点方式
在symbolic 里面symbol里面写入已知的系统方法,例如

然后就会出现下面这种情况

说明拥有alloc系统方法的类很多,然后我们在main函数中创建对象就会拦截到

3、通过汇编 :
Debug ---> Debug workflow ----> allways show,然后在系统方法前加一个断点后,就会出现这种情况

会把该方法的前后所有调用顺序都展现出来,然后再配合断点来进行调试
二、alloc流程分析
我们查找下alloc的调用流程,授信我们从官网下载objc4-750的源码,通过搜索 alloc { 我们可以发现

alloc其实是调用_objc_rootAlloc函数,再搜索_objc_rootAlloc函数

会发现_objc_rootAlloc调用的是callAlloc方法,再搜索callAlloc函数

然后一步一步分析首先看第一个obj对象

然后查看calloc函数

其中calloc函数意思是开辟一个内存空间,cls->bits.fastInstanceSize()意思是开辟一个cls类的内存空间的大小,前面__count意思是倍数,其中cls->bits.fastInstanceSize()大小是遵循内存对齐原则开辟内存的
内存对齐原则:
-
1、数据成员对⻬规则:结构体(struct)(或联合体(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是数组,结构体等)的整数倍开始(比如int为4字节,则要从4的整数倍地址开始存储。
-
2、结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储.(struct a里存有struct b,b里有char,int,double等元素,那b应该从8的整数倍开始存储.)
-
3、收尾工作:结构体的总大小,也就是sizeof的结果,.必须是其内部最大成员的整数倍.不足的要补⻬。
内存对齐原则注意点
-
1、对象的属性需要的内存空间是8位倍数,如果不以8的倍数,CPU读起来很a耗性能高,所以以8字节为倍数,提高读取效率,以空间换时间
-
2、开辟的对象的空间如果小于16字节的分配16个字节,防止越界
我们再继续分析代码,由于calloc不在objc源码里面,是在malloc源码里面,我们下载malloc源码,查找下calloc的实现

然后进入到 retval = malloc_zone_calloc(default_zone, num_items, size); 方法里面

这样就开辟除了一块内存空间,然后通过callBadAllocHandler将这块内存空间和cls类关联起来

如果开辟不成功就会调用initInstanceIsa方法去

再分析这一块

首先查看class_createInstance函数的实现

然后再查看_class_createInstanceFromZone函数的实现

当满足条件时候

先给objc开辟一个内存空间,然后将类cls的isa指针给obj,我们查看下initInstanceIsa的实现

然后查看initIsa函数实现
