我们在分析对象创建的流程时发现,对象在创建之前,第一步是先计算实例对象所占空间大小。所以我们今天来看一下是如何创建的。
talk is cheap, show me the code!我们就从代码中寻找我们的答案。
计算内存大小
size_t size = cls->instanceSize(extraBytes); |
首先,在获取对象实例空间大小时,要求所有的对象至少为 16 字节,为什么是 16 字节呢?
// Class's ivar size rounded up to a pointer-size boundary. |
其次,对象的地址进行了一个 字节对齐 的操作。在64
位架构上进行 8
字节对齐,32
位机器上进行4
字节对齐。字节对齐这段代码只有一行:
(x + WORD_MASK) & ~WORD_MASK; |
我们来分析下这行代码:
WORD_MASK
是一个宏定义,那么就可以针对不同平台有不同的值,这里就是针对 64/32 位架构做了区分。
(x + WORD_MASK) & ~WORD_MASK
, 我们用一个例子来说明,以8
字节对齐为例:
uint32_t x = 25; |
我们在 lldb 里面将 x
与 WORD_MASK
都转化成二进制计算:
27 011011 |
字节对齐的操作之后,对象的空间大小是**8
的倍数**,那么对象的起始地址也必定是8
的倍数。
还有另外一种方法也能达到8
字节对齐的效果,即
(x + WORD_MASK) >> 3 << 3 |
如果要符合不同平台,需要定义个宏定义,其实上面的宏定义里面已经定义好了,即
(x + WORD_MASK) >> WORD_SHIFT << WORD_SHIFT |
这是一个例子
现在我们给出我们的一个类 SMPerson
,计算一下他所占的内存空间:
@interface SMPerson : NSObject |
OC 类在底层实现还有一个隐藏的 isa
指针,这里如果不考虑成员变量在内存中是如何分布(至于这里为什么不需要考虑内存分布,是因为这部分编译器已经帮我们处理好了),计算出来的实例对象的大小为40
字节,下面我们验证一下:
在 main.m 文件中
int main(int argc, const char * argv[]) { |
控制台输出:
2019-12-22 23:26:50.541712+0800 objc-debug[13935:27611066] 40 |
是不是感觉自己棒棒哒 (๑•̀ㅂ•́)و✧