alloc底层流程
黑暗不会永驻,黎明即将到来!
学习了oc这么多年,关于底层的东西也是很模糊,这个系列的文章将带大家一起发现探索关于oc的底层知识。正所谓万物皆对象,所以我们先从对象的创建开始吧!
alloc对象的指针地址和内存
- 首先有一个疑问:对象是怎么创建的?由谁创建的?alloc? init?还是alloc init一起呢?上代码!!!
LGPerson *p1 = [LGPerson alloc];
LGPerson *p2 = [p1 init];
LGPerson *p3 = [p1 init];
// 打印之前也会有一些疑问:
// alloc 是不是有了内存 指针?
// init 内存是不是一样?
NSLog(@"%@-%p-%p",p1,p1,&p1);
NSLog(@"%@-%p-%p",p2,p2,&p2);
NSLog(@"%@-%p-%p",p3,p3,&p3);
// 输出打印:
<LGPerson: 0x600000fb4480>-0x600000fb4480-0x7ffeeac99180
<LGPerson: 0x600000fb4480>-0x600000fb4480-0x7ffeeac99178
<LGPerson: 0x600000fb4480>-0x600000fb4480-0x7ffeeac99170
复制代码
我们可以发现p1,p2,p3的内存是指向的同一个地方,但是各自的指针地址却不一样,如下图。
由此得知,对象的创建是由alloc创建的,那它怎么做到的? init 有何用?接下来让我们继续探索。
底层探索的三种方法
- 符号断点:
打上断点后运行程序(以模拟器为例),control + step into
点住往下走
创建断点
继续过掉当前断点
走到libobjc.A.dylib动态库的objc_alloc方法
- 汇编 跟流程 – 符号断点
同符号断点一样操作
3.通过已知符号断点确定位置
汇编结合源码调试分析
定位objc源码
苹果开源源码地址:
opensource.apple.com
opensource.apple.com/tarballs/
可以下载底层源码进行跟踪调试分析代码,下载好的源码可能会编译不过去,报各种错,大家可以去看这篇文章 juejin.cn/post/684490… 来解决源码配置的问题。
编译器优化
在工程对应Target的Build Settings中,找到optimization level这一项
debug模式一般选None fast可以优化编译器编译速度,减少汇编代码
alloc的主线流程
跟踪源码,探查alloc底层实现
核心方法一:计算需开辟内存的大小
十六字节对齐
核心方法二:开辟内存 返回内存地址指针
核心方法三:指针与类绑定
到此alloc完成
字节对齐
-
对象的内存大小由什么决定?–>成员变量
-
isa为啥是8字节?–>继承于NSObject
字节对齐原理
(x + WORD_MASK) & ~WORD_MASK
例如:
(8 + 7)& ~7 --> 15 & ~7 8字节对齐 取8的整数倍
(8 + 7) >> 3 << 3
二进制显示
15:0000 1111
7: 0000 0111
~7:1111 1000
15 & ~7:0000 1000 = 8
复制代码
- 为什么是8的倍数,而不是16或者32甚至更大呢?
首先如果内存不一样大,寄存器读取不断变化,会导致读取的速度变慢
都以8字节读取会变快,以空间换取时间
在各种数据类型里,最大的为8字节
对象的内存空间
0x011d800100008491:Isa