二、alloc的流程
在进行源码跟踪之前先了解一下以下的三个方法:
sizeof:判断数据类型或者表达式长度的运算符,返回一个变量或者类型的大小(以字节为单位)
class_getInstanceSize:返回类实例的大小。
malloc_size:系统分配的内存大小
sizeof 和 class_getInstanceSize 是获得这个对象需要占用的内存。malloc_size 是获得系统会给这个实例对象分配的内存。

通过打印,可以知道 sizeof、class_getInstanceSize 与 malloc_size 打印的结果是不一样的。
为什么?来看一下到底怎么回事。
alloc 源码跟踪:
我们打开可编译的源码,对alloc跟踪,大致的流程是这样的:alloc -> _objc_rootAlloc -> callAlloc -> _objc_rootAllocWithZone -> _class_createInstanceFromZone,但在运行的时候,alloc的流程调用方法并不完全是这样,后面会有解释!
它的核心方法是_class_createInstanceFromZone,来看一下源码的实现:

这个方法共有三个核心步骤,先来看看第一个。
1. instanceSize -> 计算对象需要开辟的内存。
先来看一下instanceSize的源码实现:

大致可以分两个步骤:
- 缓存中快速计算内存大小:
cache.fastInstanceSize。 - 计算 isa 和成员变量需要的内存大小(
alignedInstanceSize),如果不足16字节的,补齐16字节
fastInstanceSize 的源码实现:

可以看到,在最后,会调用一个 align16 的函数,来看一下这个函数的实现:

发现,这是一个内联函数,并且,它的作用就是,传一个size_t,通过size_t的大小,计算并返回size_t 16字节对齐后的大小。
为什么是16字节对齐,其实是可以算出来的,假设参数 x = 8,就变成了 (8 + size_t(15)) & ~size_t(15),~有取反的作用,这个值在二进制中的0变成1,1变成0的意思。具体的算法看下图:

通过这张图可以得知,align16 就是进行16字节对齐的一个函数。
alignedInstanceSize 的源码调用
看一下在源码中 alignedInstanceSize 干了什么:

可以看到,alignedInstanceSize就是拿到类的成员变量的大小,进行word_align。word_align是什么意思呢?来看一下源码实现:

说白了,alignedInstanceSize的最终目的就是为了拿到类的成员变量的大小进行8字节对齐,为什么是8字节对齐呢?其实和align16的原理一样。
这也是为什么在下面会有不满16字节,补齐16字节的判断。
另外,instanceSize方法只是计算出当前类开辟内存时需要的大小,不能决定在运行时当前类所占用的内存就是这个大小,决定当前类在运行时占用的内存大小由 calloc 函数决定。下面,来看一下这个calloc。
2. calloc -> 开辟内存。
在 libmalloc-317.40.8 源码中,calloc的流程:
calloc -> _malloc_zone_calloc -> default_zone_calloc -> nano_calloc -> _nano_malloc_check_clear -> segregated_size_to_fit。
直到 segregated_size_to_fit 方法中,查看 NANO_REGIME_QUANTA_SIZE 的定义发现以下宏定义:
#define SHIFT_NANO_QUANTUM 4
#define NANO_REGIME_QUANTA_SIZE (1 << SHIFT_NANO_QUANTUM) // 16
#define NANO_QUANTA_MASK (NANO_REGIME_QUANTA_SIZE - 1)
#define NANO_SIZE_CLASSES (NANO_MAX_SIZE/NANO_REGIME_QUANTA_SIZE)
可以得知,calloc 开辟内存是遵守 16 字节对齐的。什么意思呢,就是在instanceSize计算出当前类的内存大小后,由calloc对当前类的内存大小进行16字节对齐,这个才是系统分配给当前类在运行时真正占用的内存大小。
这就是前面提到的 sizeof、class_getInstanceSize 与 malloc_size 打印的结果是不一样的原因。
3. initInstanceIsa
initInstanceIsa最终会调用initIsa,来看一下initIsa的源码实现:

其实这个方法就是将 cls 和 isa 绑定在一起,进行关联。

浙公网安备 33010602011771号