本文主要探索alloc
的底层实现原理
- 大家可以通过 Apple source 在 路径自行下载
objc4-781
源码
首先我们有一个疑问,那就是alloc是如何创建对象,开辟内存,并且将对象与内存关联起来的呢?我们带着这些问题打开源码来一探究竟。
- 1.首先根据
main
函数中的LGPerson
类的alloc
方法进入alloc
方法的源码实现(即源码分析开始)
2.跳转至_objc_rootAlloc
底层实现
3.跳转至callAlloc
4.接下来流程会走到callAlloc
的具体实现
5.进入_class_createInstanceFromZone
源码
这里展示了三个重点方法:
1.cls->instanceSize
计算内存大小
2.calloc
开辟内存方式
3.obj->initInstanceIsa
isa与类绑定在一起
由此可得出alloc的流程图如下
问题一:系统是如何计算内存空间大小的,即instanceSize
的源码流程
-
跳转到
instanceSize
源码实现如下图,流程接下来会走进下图标识处
-
跳转至函数
fastInstanceSize
的源码实现如图
-
align16
源码实现
-
align16
算法解读如下图:其中x为一个对象,所占内存8字节
此算法说明:由此图看出,与上之后后四位全部抹零了,也就是说保留了16的倍数,16以下全部抹零。由此得出结论,此算法的目的就是16字节对齐。
为什么要16字节对齐?
- 内存对齐是在计算机中排列数据、访问数据的一种格式,简单来说就是前面的地址必须是后面的地址正数倍,不是就补齐,系统在读取内存的时候,不会随时改变自己读取的长度,这么做的目的是为了节约性能,方便读取。
- 首先我们知道任何对象都具备一个
isa
的属性(isa
是一个结构体指针占8字节) ,假设一个对象没有属性,没有内存的情况下,就已经占了8字节,如果按照8字节对齐方式进行存储时会发现对象是一个挨着一个的,前一个对象挨着后一个对象isa,这样就容易导致一些访问错误、野指针的问题出现。为了使整个内存更加安全,所以预留了一些位置。
到此我们了解了alloc
的源码实现,那么init
又做了什么呢?
init原理
-
查看init源码实现
说明
init
只返回了self
,什么也没有做,那么 init 有什么作用呢?
这里是利用了工厂设计模式,init
的作用是方便子类自定义重写,预留自定义内容的接口,给子类自由发挥的空间。比如array和普通的一个对象,初始化之后,所具有的东西是不一样的,根据用户的需要,可以定制化开发。给开发人员提供一个构造方法的入口。
new
-
进入new的源码实现可看到如下图:
new
是callAlloc
和init
的结合,等同于[alloc init]
,如果子类不想自定义重写的话,直接可以用new
进行初始化开辟内存。