前言程序员
每一个特定的平台上的编译器都有本身的默认“对齐系数”(也叫对齐模数)。咱们能够经过预编译命令#pragma pack(n)
,n=一、二、四、八、16 来改变这一系数,其中的n就是要指定的“对齐系数”。咱们iOS编译器Xcode的对齐系数就是8。安全
Struct
或者Union
的数据成员)第一个数据成员放在偏移为0的位置。之后每一个数据成员的位置为min(对齐系数,自身长度)的整数倍,下个位置不为本数据成员的整数倍位置的自动补齐。struct Struct1 {
double a;
int b;
char c;
short d;
}myStruct1;
struct Struct2 {
int a;
double b;
int c;
char d;
}myStruct2;
NSLog(@"myStruct1 - %lu",sizeof(myStruct1));
NSLog(@"myStruct2 - %lu",sizeof(myStruct2));
复制代码
myStruct1 - 16
,myStruct2 - 24
.分析:bash
Struct1类型 | 位置 | 补齐 | Struct2类型 | 位置 | 补齐 |
---|---|---|---|---|---|
double a | [0 - 7] | 0 | int a | [0 - 3] | 4 |
int b | [8 - 11] | 0 | double b | [8 - 15] | 0 |
char c | [12 - 12] | 1 | int c | [16 - 19] | 0 |
short b | [14 - 15] | 0 | char b | [20 - 20] |
Struct1
总体对齐以后:大小为16。Struct2
总体对齐以后:大小为24。struct Struct1 {
double a;
int b;
char c;
short d;
}myStruct1;
struct Struct2 {
int a;
double b;
char d;
short e;
}myStruct2;
NSLog(@"myStruct1 - %lu",sizeof(myStruct1));
NSLog(@"myStruct2 - %lu",sizeof(myStruct2));
复制代码
myStruct1 - 16
,myStruct2 - 24
.分析:post
Struct1类型 | 位置 | 补齐 | Struct2类型 | 位置 | 补齐 |
---|---|---|---|---|---|
double a | [0 - 7] | 0 | int a | [0 - 3] | 4 |
int b | [8 - 11] | 0 | double b | [8 - 15] | 0 |
char c | [12 - 12] | 1 | char c | [16 - 16] | 1 |
short b | [14 - 15] | 0 | short d | [18 - 19] |
Struct1
总体对齐以后:大小为16。Struct2
总体对齐以后:大小为24。struct Struct1 {
double a;
int b;
char c;
short d;
}myStruct1;
struct Struct2 {
int a;
double b;
char d;
struct Struct1 myStruct1;
}myStruct2;
NSLog(@"myStruct2 - %lu",sizeof(myStruct2));
复制代码
myStruct2 - 24
.分析:性能
Struct2 | 类型 | 位置 | 补齐 |
---|---|---|---|
int a | [0 - 3] | 4 | |
double b | [8 - 15] | 0 | |
char c | [16 - 16] | 7 |
咱们按照规则来算,成员为结构体的,按照结构体的本身内部数据成员的最大长度的整数倍储存。atom
Struct2 | 类型 | 位置 | 补齐 |
---|---|---|---|
double a | [24 - 31] | 0 | |
int b | [32 - 35] | 0 | |
char c | [36 - 36] | 1 | |
short d | [38 - 39] |
Struct2
总体对齐以后:大小为40。@interface XDPerson : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) int age;
@property (nonatomic, assign) long height;
@property (nonatomic, copy) NSString *sex;
@property (nonatomic) char ch1;
@property (nonatomic) char ch2;
@end
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
XDPerson *p1 = [XDPerson alloc];
p1.name = @"xiedong";
p1.age = 18;
p1.height = 180;
p1.sex = @"男";
p1.ch1 = 'a';
p1.ch2 = 'b';
NSLog(@"%lu - %lu",class_getInstanceSize([p1 class]),malloc_size((__bridge const void *)(p1)));
}
复制代码
输出结果 40 - 48。spa
objc
源码里面是能够获得验证的。malloc
源码里面segregated_size_to_fit()
能够看到是以16字节对齐的。lldb
调试查看
x/6xg p1
意思表明 读取p1
对象6段内存地址。调试
(lldb) x/6xg p1
0x600000ce0000: 0x00000001029570d0 0x0000001200006261
0x600000ce0010: 0x0000000102956098 0x00000000000000b4
0x600000ce0020: 0x00000001029560b8 0x0000000000000000
(lldb) po 0x00000001029570d0 & 0x0000000ffffffff8
XDPerson
(lldb) po 0x00000012
18
(lldb) po 0x62
98
(lldb) po 0x61
97
(lldb) po 0x0000000102956098
xiedong
(lldb) po 0x00000000000000b4
180
(lldb) po 0x00000001029560b8
男
复制代码
发现
OC
里面程序员写的属性的顺序并非内存里面的顺序,与结构体struct
仍是有必定的区别。其实这里就是编译器给进行二进制重排
产生的效果。code
isa
,是objc_object
这个基类带的数据成员。后面的章节中会有所介绍。咱们能够想一下,假设CPU先从0地址读取4字节到寄存器,这个时候内存是对齐的,一次读取4字节。而后在从1地址读取,先读取2字节,再读取2字节,而后再合成到寄存器,这个时候CPU的性能就会相对上一次下降,对整个应用程序的性能一定会产生相应的影响。对象
有时候咱们会思考为何系统开辟的内存大小会大于咱们申请的内存大小呢?按照8字节对齐的方式,申请的内存就可能已经存在多余的了,就拿上面的例子int
和两个char
就会多了两字节。