在上一篇文章中,我们了解到继承体系中的实例对象在内存中占用情况,具体可参考继承体系中的内存分布。
看完上一篇文章,不知道有没有朋友产生疑问,如果在Student类中有2个成员变量,Student的实例对象会占用多少字节的内存空间呢?
最简单的方法,直接通过代码来验证:
细心地朋友已经发现问题了,我们在Student类中新加了一个整形变量no,实际打印结果是系统为Student分配了32个字节空间,但是Student实际只占用了24个字节大小。由于Person类没有变化,还是分配了16个字节,同时占用16个字节大小。
那么为什么仅仅多了一个整形变量,Student实例对象就会有原来的16个字节变为32个字节呢,实际占用的空间也由16个字节变成了24个字节呢?
这个就是我们今天要探究的问题,内存对齐。
通过前面两篇文章的介绍,我们已经知道在iOS中,类对象其实是通过C++中的结构体实现的,那我们透过现象看本质,看看Student类的结构体长啥样。
执行命令:xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main.cpp
在生成的main.cpp文件中,搜索Student_IMPL
由于 Person_IVARS是 Pseron_IMPL类型结构体,NSObject_IVARS是NSObject_IMPL,直接将其替换,得到:
也就是说Student实例对象有4个成员变量,分别是 isa指针和三个整形变量。isa指针在64位环境下占用8个字节,每个int变量占用4个字节,也就是Student实例对象只需要20个字节就够了。但是我们通过 class_getInstanceSize() 函数得到的结果是24。
这里就是我们要探讨的第一个问题,结构体的内存对齐。
结构体的内存分布遵循一个原则,即内存大小是其成员变量中占用最大的整数倍。在这个结构体中,最大字节是8,实际需要20个,最接近20的8的倍数是24。所以Student对象实际占用24个字节。
明白了为什么占用24个字节以后,我们来解决第二个问题,为什么通过malloc_size()函数得到的却是32个字节。
这里牵涉到我们要探讨的第二个问题,系统为对象分配内存时的内存对齐。在iOS系统中,有一个内存桶的概念,每个内存桶大小固定是16个字节。当系统给Student实例对象分配空间时,发现其实际需要24个字节大小,但是每个内存桶固定位16个字节,要满足24个字节的内存空间,就直接分配2个内存桶,供Student实例对象使用,也就是我们通过malloc_size()得到的32。
总结一下,主要牵涉到两个关于内存对齐的问题:
1、为结构体分配空间时,结构体大小以结构体成员变量中字节最大的为基准,进行对齐。
2、系统为变量分配空间时,每次一16个字节为基准进行对齐,也就是说实例对象的大小一定是16的倍数。
有疑问的话,欢迎讨论。
网友评论