内存对齐
OC基本数据类型所占字节数对比
注1 :BOOL
在32位机器被定义为char、在64位机器被定义为bool
boolean_t
在32位机器被定义为unsigned int、在64位机器被定义为int
NSInteger
在32位机器被定义为int、在64位机器被定义为long
NSUInteger
在32位机器被定义为unsigned int、在64位机器被定义为unsigned long
CGFloat
在32位机器被定义为float、在64位机器被定义为double
以上多变的情况是是使用宏定义实现的,编译后可查看其实现
注2:由于C语言只会将bool的非0值置为1,因此,BOOL的使用过程中应注意在32位机器上并非只有1和0两种可能取值,取值范围是-128~127(其实也不用太在意,因为现在几乎没几个人还在用32位的手机)
内存对齐规则
- 数据成员对⻬规则
结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小
(只要该成员有子成员,比如说是数组,结构体等)的整数倍开始(比如int为4字节,则要从4的整数倍地址开始存储 - 结构体作为成员
如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储
,(struct a里存有struct b,b里有cha,int,double等元素,那b应该从8的整数倍开始存储) - 收尾工作
结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍,不足的要补⻬
先有下面三个结构体:
objectivec
struct Struct1 {
double a; // 8
char b; // 1
int c; // 4
short d; // 2
} struct1;
struct Struct2 {
double a; // 8
int b; // 4
char c; // 1
short d; // 2
} struct2;
struct Struct3 {
double a; // 8
int b; // 4
char c; // 1
short d; // 2
int e; // 4
struct Struct1 struc; // 24
} struct3;
根据上面的内存对齐规则,可计算出struct1
所占用的字节数是24,struct2
所占用的字节数是16,struct3
所占用的字节数是48,通过sizeof
也可以验证这些答案
内存对齐原因
性能
内存是以字节为基本单位,cpu
在存取数据时,是以块为单位存取,并不是以字节为单位存取。频繁存取未对齐的数据(存取未对齐的数据可能开始在上一个内存块,结束在另一个内存块,中间可能要经过复杂运算在合并在一起,降低了效率 ),会极大降低cpu
的性能。字节对齐后,会减低cpu
的存取次数,提高了cpu
的访问速率,这种以空间换时间的做法目的降低cpu
的开销
跨平台
有些硬件平台并不能访问任意地址上的任意数据的,只能处理特定类型的数据,否则会导致硬件层级的错误。
有些CPU(如基于 Alpha,IA-64,MIPS,和 SuperH 体系的)拒绝读取未对齐数据。当一个程序要求这些 CPU 读取未对齐数据时,这时 CPU 会进入异常处理状态并且通知程序不能继续执行。
举个例子,在 ARM,MIPS,和 SH 硬件平台上,当操作系统被要求存取一个未对齐数据时会默认给应用程序抛出硬件异常。所以,如果编译器不进行内存对齐,那在很多平台的上的开发将难以进行。
OC对象内存对齐
在之前的文章中已经了解到OC对象实际上是结构体,结构体成员变量的内存排序遵循内存对齐规则,那么对象属性的内存排序也遵守内存对齐规则
创建一个Person类:
objectivec
@interface Person : NSObject
@property (nonatomic, assign)double a;
@property (nonatomic, assign)char b;
@property (nonatomic, assign)int c;
@property (nonatomic, assign)short d;
@end
Person* person = [[Person alloc] init];
person.a = 7.7;
person.b = 's';
person.c = 7;
person.d = 7;
NSLog(@"%zd %zd", class_getInstanceSize([Person class]), malloc_size((__bridge const void *)(person))); // 24 32
通过输出我们可以看出成员变量所占内存大小是24字节,其中isa
要占8个字节,其余成员占16个字节,所以至少需要24字节
操作系统在分配内存时,也会有"内存对齐",所以size是24,malloc_size
返回 32,即系统实际分配内存32字节(从内存对齐的角度也可以算出32)
总结
内存对齐可以提高cpu的存取效率同时提升安全性,会有部分内存的浪费,但是系统又会根据数据存储情况进行内存优化,尽可能降低内存浪费,这样即保证了性能又减少了浪费