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);
输出结果如下:
从上面测试可以看出:
p1
、p2
、p3
三个对象的对象地址是一致
,指针地址不一致
p4
与p1
、p2
、p3
这三个对象的对象地址以及指针地址都不一致
为什么呢?从下图我们就会明白
总结:
alloc
有开辟内存的作用,而init
并没有开辟新内存- 栈的内存地址开辟是从
高
到低
,堆的内存开辟是从低
到高
alloc底层探索-方法
今天学习到了底层源码的几种查看方法,就是简单对象的alloc方法源码位置查看。
方法一、下符号断点定位方法
-
下一个alloc的符号断点,但先关闭
-
当执行到代码alloc的时候,再打开这个符号断点
-
继续运行,则会看到alloc方法所在源码库libobjc.A.dylib
方法二、control+step into
-
在alloc的代码加断点
-
执行到断点后,按住ctrl的同时点击xcode的step into,一直进入到线程里,可以看到执行了objc-alloc方法
-
下objc-alloc的符号断点
-
继续执行后,就可以看到alloc方法所在源码库libobjc.A.dylib
方法三、汇编查看
-
打开汇编(Debug->Debug WorkFlow -> Always show disasesmbly)
-
在alloc的代码位置进行断点,执行到汇编后,可以看到objc-alloc这个方法执行,这时候复制objc-alloc下一个符号断点
-
继续执行,就可以看到源码位置
alloc底层探索-源码
查看到源码所在库之后,打开苹果开源代码地址:opensource.apple.com/tarballs/ 库文件libobjc.A.dylib,搜索objc可以找到源码,有多个版本,找到最新的去下载查看,效果如下:
根据前面所诉,我们可以取得一份苹果的底层objc的源码库,具体源码及源码可编译配置后续补充
alloc底层探索-alloc流程
采用前面的探索方法,通过底层代码,跟踪alloc流程,可以知道alloc流程如下:
从流程跟进可知,alloc主要是用于开辟内存空间,核心代码如下:
cls->instanceSize
:要开辟多少内存
calloc
:怎么开辟空间
obj->initInstanceIsa
:关联类和开辟的指针地址
跟进instanceSize
方法
发现最终我们执行到了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在读取的时候,按照块读取就可以,效率更高,同时还不容易混乱。