前言程序員
每一個特定的平臺上的編譯器都有本身的默認「對齊係數」(也叫對齊模數)。咱們能夠經過預編譯命令#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
就會多了兩字節。