题记
上一篇我们提到NSObject对象在内存所占大小,由此引出的问题,其他的OC对象比如我们自定义一个继承自NSObject的Person类,在内存中又是怎样的分布,是否符合同样的的规律?
准备工作
-
我们新建一个继承自NSObject的Person类,帮它增加三个成员变量,那么Person又会占据多大的内存
- 照惯例我们还是使用runtime和malloc的函数来查看一下,会发现得到的是24和32,但是为什么是24和32呢?
论证
- 打开main.m所在的文件夹,在终端输入
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp
,得到重新编译后的C++文件,并把它拽入Xcode中,通过搜索可以看到Person在底层C++的实现,正如我们看到的,一个NSObject对象占8个字节,一个int占4个字节,那么一共占8+4+4+4=20个字节,为什么会打印出来24和32呢?
-
这里涉及一个内存对齐原则,系统在计算结构体大小时,分配的空间是所需最大内存的倍数,在Person的结构体中,需要最大的内存是8个字节,所以当实际使用20个字节时,实际分配的是3 * 8 = 24个字节,所以Person指向的内存大小为24个字节
- 我们也可以通过sizeof这个函数,打印出Person_IMPL这个结构体的长度,进一步论证Person转成C++结构体后的实际长度为24
疑问
- 那为什么通过malloc函数打印出来的长度会是32呢?我们还是从malloc的源码入手分析一波,打开网址
https://opensource.apple.com/tarballs/
,搜索libmalloc,选择编号最大的一份下载
- 解压后打开源码,我们搜索bucket(可以理解为桶,容器),我们可以从注释看到,其实iOS系统在给我们分配内存时有它自己的原则,分配的大小都是16的倍数,所以即使Person_IMPL结构体为24,但是系统也会为它分配32个字节大小的内存
总结
- 系统在计算Person时只需要24个字节就够用了,但是实际上在OC分配规则下,系统实际分配的内存空间是32个字节
-
我们在源码里直接搜索malloc.c,可以看到其实OC内存分配的实现方法并不止一种,只是我们刚刚的这个例子用到的分配方法是这个而已。更多的内存分配规则如果大家感兴趣可以进一步去了解。