最新alloc源码调用流程
查看alloc调用底层的方法
通过查看汇编分析,然后在通过汇编分析的方法添加符号断点查看
先将在alloc初始化处添加断点
然后Debug->Debug Workflow->Always Show Disassembly来查看汇编中的调用
查看汇编,当前会停在我们当前要执行的函数,查看汇编发现,想下会调用_objc_alloc方法
此时我们在通过添加符号断点,将_objc_alloc添加
继续执行,我们发现确实执行了objc_alloc方法,接下来我们需要到objc源码中查看后面的流程
查看objc源码
首先我们通过一个可以运行的objc项目来进行演示,可运行的objc项目在文章末尾自行下载
我们通过按commd+鼠标左键进入alloc的调用,发现就直接进入到了objc的alloc方法
alloc中调用_objc_rootAlloc
objc_rootAlloc继续调用callAlloc
callAlloc会调用_objc_rooAllocWithZone方法
_objc_rooAllocWithZone中会调用_class_createInstanFromZone方法进行内存分配和实例对象创建
_class_createInstanFromZone首先会根据传入对象的属性来计算内存大小,然后在创建一个size大小obj对象,最后将obj对象与cls也就是我们传入的类进行关联,最后将创建好的对象返回
内存对齐
计算机编码过程中内存分配是有一定规则的,一般长以8的倍数进行分配,但是iOS中比较特殊是以16的倍数进行分配的。
由于内存比较小,所以内存在分配时内存地址一般是连续的,内存读取的方式是以块状读取,那么当内存按照最小的块大小进行倍数分配时,当读取的时候可以防止读取出错。
iOS对象都有一个isa指针,isa就是对象在内存的首地址,每个指针占8字节,但是对象还可能有自己的属性,那么初始的收我们就默认分配的最小内存就是16字节,而且内存是按16的倍数进行对齐。
下面我们查看源码:
如果计算出来的内存如小于16字节,那么直接返回16字节
内存对齐计算方式:x+size_t(15))&~size_t(15),将计算的内存大小与上一个按位取反的15
如计算出内存需要分配20那么内存对齐过程如下
20的二进制 0000 0000 0001 0100
15 的二进制 0000 0000 0000 1111 +
————0000 0000 0010 0011
~15 二进制 -1111 1111 1111 0000 &
————0000 0000 0010 0000 == 32
所以会20字节内存对齐后会分配32字节
init源码
通过源码查看,init返回的其实就是自身对象,不会创建新的对象
那么为什么还要有init方法呢?
init方法是我们对象初始化时的构造方法,开发者可通过重写init方法,来重构自己的构造方法,在初始化的时候可以带入自己自定义的参数来快速初始化对象。
new源码
我们可以看到,new实际上就是直接调用alloc后又帮我们调用了一次init方法
其实new防反就等同于alloc + init方法
看完原理看代码
int main(int argc, const char * argv[]) {
@autoreleasepool {
YJCar *car1 = [YJCar alloc];
YJCar *car2 = [car1 init];
YJCar *car3 = [car1 init];
NSLog(@"%@--%p--%p", car1, car1, &car1);
NSLog(@"%@--%p--%p", car2, car2, &car2);
NSLog(@"%@--%p--%p", car3, car3, &car3);
}
return 0;
}
复制代码
证明此时car1、car2、car3是同一个对象,都引用这car1
通过代码log打印方式
int main(int argc, const char * argv[]) {
@autoreleasepool {
YJCar *car1 = [YJCar alloc];
YJCar *car2 = [car1 init];
YJCar *car3 = [car1 init];
car1.name = @"奔驰";
NSLog(@"%@--%@--%@", car1.name, car2.name, car3.name);
car3.name = @"BMW";
NSLog(@"%@--%@--%@", car1.name, car2.name, car3.name);
}
return 0;
}
复制代码
通过窥探内存方式
(lldb) x car1
0x6000020ff780: e8 55 15 00 01 00 00 00 40 00 15 00 01 00 00 00 .U......@.......
0x6000020ff790: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
(lldb) x/4g car1
0x6000020ff780: 0x00000001001555e8 0x0000000100150040
0x6000020ff790: 0x0000000000000000 0x0000000000000000
(lldb) x/4g car2
0x6000020ff780: 0x00000001001555e8 0x0000000100150040
0x6000020ff790: 0x0000000000000000 0x0000000000000000
(lldb) x/4g car3
0x6000020ff780: 0x00000001001555e8 0x0000000100150040
0x6000020ff790: 0x0000000000000000 0x0000000000000000
(lldb) po 0x0000000100150040
奔驰
复制代码
看到这里在回答面试官的int的初始化过程和init与alloc及new的关系就可以向切菜一样了吧
我也是在重新复习底层知识,如果本文对大家有帮助希望,希望大家收藏点赞。
也欢迎与各位大佬互动探讨,谢谢!