alloc底层探索

162 阅读4分钟

alloc底层探索-初

首先得说,这是第一次去探索苹果的底层代码,之前的所有oc开发,都只是基于xcode上可见的功能,偶尔看到底层代码,也都觉得头大,一掠而过,作为一个已经IOS行业呆了5、6年的人来说,显然是跟不上节奏的,学习是刻不容缓的。

首先我们来做一个小测试,简单验证底层指针,代码如下:

    LGPerson *p1 = [LGPerson alloc];
    LGPerson *p2 = [p1 init];
    LGPerson *p3 = [p1 init];
    
    LGPerson *p4 = [LGPerson alloc];
    
    NSLog(@"%@-%p-%p",p1,p1,&p1);
    NSLog(@"%@-%p-%p",p2,p2,&p2);
    NSLog(@"%@-%p-%p",p3,p3,&p3);
    NSLog(@"%@-%p-%p",p4,p4,&p4);

输出结果如下:

image.png

从上面测试可以看出:

  • p1p2p3 三个对象的对象地址是一致指针地址不一致
  • p4p1p2p3这三个对象的对象地址以及指针地址都不一致

为什么呢?从下图我们就会明白

image.png

总结:

  • alloc有开辟内存的作用,而init并没有开辟新内存
  • 栈的内存地址开辟是从,堆的内存开辟是从

alloc底层探索-方法

今天学习到了底层源码的几种查看方法,就是简单对象的alloc方法源码位置查看。

方法一、下符号断点定位方法

  1. 下一个alloc的符号断点,但先关闭

  2. 当执行到代码alloc的时候,再打开这个符号断点

  3. 继续运行,则会看到alloc方法所在源码库libobjc.A.dylib

方法二、control+step into

  1. 在alloc的代码加断点

  2. 执行到断点后,按住ctrl的同时点击xcode的step into,一直进入到线程里,可以看到执行了objc-alloc方法

  3. 下objc-alloc的符号断点

  4. 继续执行后,就可以看到alloc方法所在源码库libobjc.A.dylib

方法三、汇编查看

  1. 打开汇编(Debug->Debug WorkFlow -> Always show disasesmbly)

  2. 在alloc的代码位置进行断点,执行到汇编后,可以看到objc-alloc这个方法执行,这时候复制objc-alloc下一个符号断点

  3. 继续执行,就可以看到源码位置

alloc底层探索-源码

查看到源码所在库之后,打开苹果开源代码地址:opensource.apple.com/tarballs/ 库文件libobjc.A.dylib,搜索objc可以找到源码,有多个版本,找到最新的去下载查看,效果如下:

4028335-ee1456a211cbf154.png

根据前面所诉,我们可以取得一份苹果的底层objc的源码库,具体源码及源码可编译配置后续补充

alloc底层探索-alloc流程

采用前面的探索方法,通过底层代码,跟踪alloc流程,可以知道alloc流程如下:

image.png

从流程跟进可知,alloc主要是用于开辟内存空间,核心代码如下:

2.jpg

cls->instanceSize:要开辟多少内存

calloc:怎么开辟空间

obj->initInstanceIsa:关联类和开辟的指针地址

跟进instanceSize方法

image.png

image.png

image.png

发现最终我们执行到了align16这个方法 align16其实是一种算法,16进制对齐的算法 详解: 比如我们传进来的x值是40

size_t(15)实际值就是15,这个表达式转换一下就是:

=> (x + size_t(15)) & ~size_t(15)

=> (40 + 15) & ~15

=> 55 & ~15

15的二进制表达:0000 0000 0000 1111

15进行取反 :1111 1111 1111 0000

55的二进制表达:0000 0000 0011 0111

得出结果: 0000 0000 0011 0000 => 16的倍数,也就是16字节对齐

这里结果就是16进制对齐了。

那么,为什么要16进制对齐呢?

回答:这是空间换时间~

字节是内存的单位,1内存也叫做1字节。
但CPU在读取内存时,不是以字节为单位读取,而是以‘块’为单位,所以‘块’的大小就是内存存取的尺度。
如果不对齐的话,在我们频繁的存取内存的时候,CPU就需要花费大量的时间去分辨你要读取多少字节,这就
会造成CPU的效率低下,如果想要CPU又有效又不减少存取次数的话,那就需要找一个规范,这个规范就是字
节对齐。

那么,又为什么是16字节对齐,而不是8进制对齐呢?

苹果采取16字节对齐,是因为OC的对象中,第一位叫isa指针,它是必然存在的,指针就是8个字节,就算
你的对象中没有其他的属性了,也一定有一个isa,那对象就至少要占用8位字节。如果以8位字节对齐的话,
如果连续的两块内存都是没有属性的对象,那么它们的内存空间就会完全的挨在一起,是容易混乱的。
以16字节为一块,保证了CPU在读取的时候,按照块读取就可以,效率更高,同时还不容易混乱。