OC底层原理之-0C对象(上)对alloc理解

上图打印的结果为: 经过结果可知p1,p2,p3的对象地址都是同样的,指针指向地址一样也是同样的,可是p1,p2,p3的指针地址不一样。 经过上面打印能够作以下猜想:alloc对对象进行了建立和内存分配,而init只是建立指针指向已建立好的内存地址。猜想对不对,咱们看下alloc和init的代码执行过程。 咱们经过这样设置断点: 运行(刚开始将alloc断点放过,等运行到咱们p1的alloc位置再打开),下一步,发现断点进入到_objc_rootAlloc 还用一样的方法设置_objc_rootAlloc断点,发现进入下图: 这方法咱们看到有两个看得懂的方法_objc_rootAllocWithZone,以及objc_msgSend 咱们发现这种方法来看流程缺点很明显,首先是慢,每进入一个方法都要打相对应的断点。还有就是中间不少内容看不到,不适合。上面只是提供一个看内部实现的方法,最好的仍是看苹果开源的代码 咱们下载objc源码,看到_objc_rootAlloc进入callAlloc,但实际运行的时候,咱们发现跟咱们上面直接断点看到的是有出入的,它直接进的objc_alloc,后面补充:之因此没有进alloc而是进了objc_alloc,查资料说的是在编译期的时候若是符号绑定失败了就会触发一个这样的修复操做,调用fixupMessageRef方法,明显的能看到 if (msg->sel == SEL_alloc) , msg->imp = (IMP)&objc_alloc,将alloc方法和objc_alloc方法进行交换。(后面分析发现,咱们断点打的alloc,并无打objc_alloc断点,其实都是从objc_alloc开始,后面用消息发送方式去调用了alloc方法,来到咱们alloc断点位置) 咱们继续往下走,发现此时进入callAlloc直接进入objc_msgSend方法,调用的消息转发,消息转发去调用alloc方法 继续往下走,断点走到这了(其实先走的alloc方法后跳到下面方法) 继续(注意上面图中的callAlloc方法的传参:false/checkNil/,true/allocWithZone/跟第一次objc_alloc方法中callAlloc方法传参:true/checkNil/,false/allocWithZone/)经过语义可知:第一次传参是须要检查是否为nil,没有重写allocWithZone,第二次传参是不须要检查是否为nil,可是重写了allocWithZone. 红框字面意思快速跟慢速,能够理解为是否编译优化(感受就是debug跟release不知道对不对)下一步,进入_objc_rootAllocWithZone 继续下一步进入:_class_createInstanceFromZone(主角登场了) 为啥说是主角呢?咱们先总览整个方法 整个方法包含开辟内存,内存很isa绑定。继续下一步,红框内的方法是给size赋值,这个size咱们在整个方法里看到是开辟内存空间大小的。咱们看下这个方法instanceSize看看size怎么来的 看下这个方法,注意红框,红框内容是size不足16字节,就返回16字节,这就肯定内存空间的size最小是16字节。 咱们进入hasFastInstanceSize方法看看 其中__builtin_constant_p(extra)判断extra是否为编译常数,整个方法查资料获得的是这个方法判断是否有缓存,具体怎么判断后面知道了再补充。 回到instanceSize方法,若是有缓存就直接返回缓存就会调用返回size,看下fastInstanceSizefan方法,注意红框内容 红框的方法是个算法,就是为了保证返回的内存地址大小永远是16字节的倍数。这就是传说中的内存对齐(之因此内存对齐是为了提升CPU读取效率,这也是苹果的规定) 回到_class_createInstanceFromZone打印返回的内存 发现返回内存是32字节(为啥是32字节?由于有属性这个自定义对象有两个字符串属性,一个int对象,应该是:8+8+8+4 = 28,取16的倍数为32),继续 obj = (id)calloc(1, size);这个方法为开辟内存为32字节的内存空间 咱们验证下这个方法是不是建立了内存 执行这个方法前打印obj,结果:LGPerson 此时在打印obj为内存地址 执行红框后的方法,发现再打印obj就是咱们常打印的结果,因此说initInstanceIsa就是将内存地址跟LGPerson的isa指针进行绑定,此时obj的alloc完成。 总结下以下图 alloc流程(咱们看到自定义对象在判断是否存在自定义allocWithZoon是不存在的) 咱们看下若是是NSObject对象是什么状况 调试发如今判断是否存在自定义allocWithZoon判断是存在的 后面就同样了 为何自定义对象的自定义allocWithZoon是不存在的,而NSObject存在呢? 咱们看第一次调用的objc_alloc,其中checkNil为true,allocWithZone为false,由于第一次进来fastpath(!cls->ISA()->hasCustomAWZ())中的自定义对象cls尚未指针isa,因此为false。走objc_msgSend,会再次调用callAlloc方法,可是此时的参数checkNil为false,allocWithZone为true。由于以前调用alloc方法,经过send_message方式调用了initialize类方法,自定义对象isa指针已经存在了(自定义类不存在自定义的allocWithZoon,但它父类NSObject是有的)。 可是NSObject类不一样,由于他是系统类,在编译的时候,它的isa指针已经存在了,因此为true(后面感受不对) 补充:initialize方法会在第一次初始化该类以前调用。NSObject在运行的时候,别处已经初始化过了,因此在咱们对NSObject进行alloc时,initialize已经调用,isa指针已经存在 这也就是为何自定义对象会走两边callAlloc,而NSObject只走一遍的缘由。 补充:经过上面的解释,能够肯定,相同类屡次alloc,第一次fastpath(!cls->ISA()->hasCustomAWZ())为false,但以后都应该为true,也就是不在走_objc_rootAlloc方法。以后的验证也证实这样的猜想是对的 上面就是对OC对象alloc的理解,若是理解有什么问题,望指正,谢谢!算法

相关文章
相关标签/搜索