对象原理以及调试方法

2019-12-18  本文已影响0人  海浪萌物

当我们调试时候不知道一个系统方法后面干了些啥,调用了哪些动态库的时候,我们可以通过下断点方式进行调试,有三种方式

1、断点调试

在调用系统方法前加一个断点,然后按住control键,点击in键,也就是 image.png
这个键,一步一步跳转就能看到该方法调用的顺序,例如 image.png
就能知道alloc调用了objc_alloc方法

2、下符号断点方式

在symbolic 里面symbol里面写入已知的系统方法,例如 image.png
然后就会出现下面这种情况 image.png
说明拥有alloc系统方法的类很多, image.png

3、通过汇编 :

Debug ---> Debug workflow ----> allways show,然后在系统方法前加一个断点后,就会出现这种情况, image.png

会把该方法的所有调用顺序都展现出来

二、alloc流程

我们查找下alloc的调用流程,授信我们从官网下载objc4-750的源码,通过搜索alloc {我们可以发现 image.png
alloc其实是调用_objc_rootAlloc函数,再搜索_objc_rootAlloc函数, image.png
会发现_objc_rootAlloc调用的是callAlloc方法,再搜索callAlloc函数 image.png

然后一步一步分析

首先看第一个obj对象, image.png
然后查看calloc函数,
image.png

其中
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的实现,


image.png

然后进入到 retval = malloc_zone_calloc(default_zone, num_items, size);

方法里面, image.png 这样就开辟除了一块内存空间,然后通过callBadAllocHandler将这块内存空间和cls类关联起来 image.png

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


image.png 再分析这一块 image.png 首先查看class_createInstance函数的实现 image.png

然后再查看_class_createInstanceFromZone函数的实现


image.png

当满足条件时候


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

然后查看initIsa函数实现


image.png
上一篇下一篇

猜你喜欢

热点阅读