OC对象的底层探索(上)

2022-05-04  本文已影响0人  verylinming
01-alloc方法在底层的调用流程

1、在创建OC对象的时候,常用的方式就是alloc init方法,但是这两个方法底层究竟做了什么呢?

  Person *p = [Person alloc];
  Person *p1 = [p init];
  Person *p2 = [p init];      
  
  NSLog(@"%@", p);
  NSLog(@"%@", p1);
  NSLog(@"%@", p2);

从结果中可以看到,三个变量是一样的。

截屏2022-04-18 下午6.50.05.png

Xcode打开汇编:Debug -> Debug Workflow -> Always Show Disassembly

Person *p = [Person alloc];前打一个断点,运行程序,可以看到,在调用alloc时底层实际上调用了objc_alloc

截屏2022-04-18 下午6.48.55.png

接下来打一个全局objc_alloc符号断点,然后跳到objc_alloc方法内部。

截屏2022-04-18 下午6.56.24.png 截屏2022-04-18 下午6.59.17.png

一步一步断点调试,最终会执行objc_msgSend方法。此时分别打印rdi和rsi寄存器,可以看到objc_msgSend实际上就是Person类在调用alloc方法(po打印不出地址内容时,可以将地址强转为char *类型)。

截屏2022-04-18 下午7.12.26.png

此时为alloc方法下一个符号断点,查看alloc方法对应的汇编代码,可以看到alloc方法底层调用了_objc_rootAlloc方法。

截屏2022-04-18 下午7.18.45.png

点击下一步断点,进入方法内部,一步一步调试,可以看到最终调用了_objc_rootAllocWithZone方法。

截屏2022-04-18 下午7.21.49.png

截止目前,alloc方法的底层调用流程为:alloc -> objc_alloc -> objc_msgSend -> alloc -> _objc_rootAlloc -> _objc_rootAllocWithZone

打开苹果官方开源代码链接,下载最新objc4-838.1文件。

然后同样新建一个Person类,并在main方法中初始化。

进入alloc方法,分别在_objc_rootAllocobjc_alloccallAlloc_objc_rootAllocWithZone等处打上断点。

运行程序,会发现第一次进入断点就走到了objc_alloc方法中,在objc_alloc中又调用了callAlloc方法。

截屏2022-04-18 下午7.43.20.png

callAlloc方法中最终又调用了alloc方法。

截屏2022-04-18 下午7.40.14.png

alloc方法中,又来到了_objc_rootAlloc方法。

截屏2022-05-04 15.03.42.png

_objc_rootAlloc方法中最终又调用了callAlloc方法,这次在callAlloc中最终调用了_objc_rootAllocWithZone方法。

截屏2022-05-04 15.06.15.png

_objc_rootAllocWithZone方法内部又调用了_class_creatInstanceFromZone方法。

截屏2022-05-04 15.02.25.png

自此,可以得到alloc方法的完整底层调用流程:alloc -> objc_alloc -> callAlloc -> objc_msgSend -> alloc -> _objc_rootAlloc -> callAlloc -> objc_rootAllocWithZone -> _class_creatInstanceFromZone

截屏2022-05-04 15.08.03.png 截屏2022-05-04 15.09.15.png 截屏2022-05-04 15.31.13.png
02-关于编译器的优化

1、在汇编代码中看不到callAlloc方法和_class_creatInstanceFromZone方法的调用,是编译器优化的结果:Build Settings -> Apple Clang - Code Generation -> Optimization Level。注意选择None不代表不优化,只是优化等级没那么高。

03-对象的内存对齐方式

1、第一节说到,alloc方法最终是在classcreateInstanceFromZone中创建的对象。查看classcreateInstanceFromZone方法的源码,其中instanceSize是计算对象需要的大小(可以看到最小16个字节),alignedInstanceSize是内存对齐算法(iOS 64位下8字节对齐),word_Align是8字节对齐算法。

截屏2022-05-04 16.33.39.png 截屏2022-05-04 16.33.58.png 截屏2022-05-04 17.49.41.png 截屏2022-05-04 18.01.56.png 截屏2022-05-04 18.01.15.png

2、instanceSize方法只是计算需要的内存空间大小,实际申请内存空间是通过calloc方法,查看calloc方法实现需要打开另外一份源码libmalloc。

截屏2022-05-04 18.16.39.png
04-对象的本质

1、对象的本质是什么?

05-结构体的内存对齐方式

1、结构体内存对齐规则总结

2、结构体内部成员变量的顺序不同时,结构体大小也会受影响。

3、结构体中的结构体不作为一个整体参与计算最大成员,但结构体中的结构体的成员变量参与。

---- 此文章内容仅为个人学习总结,仅供参考。
上一篇 下一篇

猜你喜欢

热点阅读