內(nèi)存對(duì)齊指的是結(jié)構(gòu)體中對(duì)結(jié)構(gòu)成員內(nèi)存的一系列調(diào)整师骗。通過(guò)調(diào)整offset位置通孽,減少讀取結(jié)構(gòu)成員數(shù)據(jù)需要的CPU-> 內(nèi)存讀取次數(shù)。任何對(duì)象數(shù)據(jù)在底層實(shí)際上是結(jié)構(gòu)體拙友。
對(duì)齊規(guī)則
1为狸、數(shù)據(jù)成員對(duì)齊規(guī)則:結(jié)構(gòu)(struct)(或聯(lián)合(union))的數(shù)據(jù)成員,第一個(gè)數(shù)據(jù)成員放在offset為0的地方遗契,以后每個(gè)數(shù)據(jù)成員的對(duì)齊按照#pragma pack指定的數(shù)值和這個(gè)數(shù)據(jù)成員自身長(zhǎng)度中钥平,比較小的那個(gè)進(jìn)行。
2、結(jié)構(gòu)(或聯(lián)合)的整體對(duì)齊規(guī)則:在數(shù)據(jù)成員完成各自對(duì)齊之后涉瘾,結(jié)構(gòu)(或聯(lián)合)本身也要進(jìn)行對(duì)齊知态,對(duì)齊將按照#pragma pack指定的數(shù)值和結(jié)構(gòu)(或聯(lián)合)最大數(shù)據(jù)成員長(zhǎng)度中,比較小的那個(gè)進(jìn)行立叛。
3负敏、結(jié)合1、2可推斷:當(dāng)#pragma pack的n值等于或超過(guò)所有數(shù)據(jù)成員長(zhǎng)度的時(shí)候秘蛇,這個(gè)n值的大小將不產(chǎn)生任何效果其做。
是不是有一點(diǎn)眼暈?我自己總結(jié)的計(jì)算方法如下:
內(nèi)存對(duì)齊原則 (簡(jiǎn)化版):
- 找到最大的基礎(chǔ)類(lèi)型成員 , 將其內(nèi)存長(zhǎng)度作為基準(zhǔn)
- 每個(gè)成員的offset赁还,需要是成員自己類(lèi)型的整數(shù)倍
- 放完之后妖泄,struct自身的數(shù)據(jù)需要為基準(zhǔn)的整數(shù)倍
讓我們看一個(gè)簡(jiǎn)單的數(shù)據(jù):
struct Struct1 {
double a; // 8
char b; // 1
int c; // 4
short d; // 2
}struct1;
1. 最長(zhǎng)的元素是double,基準(zhǔn)為8
2.
struct Struct1 {
double a; // 長(zhǎng)度為8 offset:0艘策,0是8的整數(shù)倍蹈胡,所以 a存放位置為 (0 - 7)
char b; // 長(zhǎng)度為1 offset: 8 8是 1的整數(shù)倍,所以 b存放位置為 (8)
int c; // 長(zhǎng)度為4 offset: 9 9不是4的整數(shù)倍朋蔫,offset后移到 12 罚渐,所以 c存放位置為 (12 - 15)
short d; // 長(zhǎng)度為2 offset: 16 16是2的整數(shù)倍,所以 d存放位置為 (16 - 17)
}struct1;
3. 最終數(shù)據(jù)成員的整體內(nèi)存占用位置為 (0 - 17)驯妄,18個(gè)字節(jié)荷并。18不是基準(zhǔn) 8 的整數(shù)倍,因此填充到24.
最終 sizeof(struct1) 的大小為 24
如果我們稍微調(diào)整下數(shù)據(jù)順序:
struct Struct2 {
double a; // 8
// 這里調(diào)整了 b青扔,c的順序
int b; // 4
char c; // 1
short d; // 2
}struct2;
1. 最長(zhǎng)的元素是double源织,基準(zhǔn)為8
2.
struct Struct2 {
double a; // 長(zhǎng)度為8 offset:0,0是8的整數(shù)倍微猖,所以 a存放位置為 (0 - 7)
int b; // 長(zhǎng)度為4 offset: 8 8是 4的整數(shù)倍谈息,所以 b存放位置為 (8 - 11)
char c; // 長(zhǎng)度為1 offset:12 12是1的整數(shù)倍,所以 c存放位置為 (12)
short d; // 長(zhǎng)度為2 offset: 13 13不是2的整數(shù)倍励两,offset后移到 14 所以 d存放位置為 (14 - 15)
}struct2;
3. 最終數(shù)據(jù)成員的整體內(nèi)存占用位置為 (0 - 15)黎茎,16個(gè)字節(jié)囊颅。16是基準(zhǔn) 8 的整數(shù)倍当悔,因此不需要填充。
最終 sizeof(struct2) 的大小為 16
成員為數(shù)組的情況:
內(nèi)存對(duì)齊原則 ( ex1):
- 找到最大的基礎(chǔ)類(lèi)型成員 , 將其內(nèi)存長(zhǎng)度作為基準(zhǔn) (如果成員為數(shù)組踢代,基準(zhǔn)不按數(shù)組總長(zhǎng)盲憎,而是按照數(shù)組元素類(lèi)型來(lái)計(jì)算)
struct Struct3 {
char a; // 1 (0)
int b[2]; // b0 b1
double c; //8
}struct3;
1. 最長(zhǎng)的元素是double,基準(zhǔn)為8
2.
struct Struct3 {
char a; // 長(zhǎng)度為1 offset:0 0是1的整數(shù)倍胳挎,所以 a存放位置為 (0)
int b[2]; // b0 長(zhǎng)度為4 0ffset:1 1不是4的整數(shù)倍饼疙,b0的offest后移到4,所以 b0存放位置為 (4 - 7)b1存放位置為 (8 - 11)
double c; //長(zhǎng)度為8 offset: 12 12不是8的整數(shù)倍慕爬,offset后移到 16 所以 d存放位置為 (16 - 23)
}struct3;
3. 最終數(shù)據(jù)成員的整體內(nèi)存占用位置為 (0 - 23)窑眯,24個(gè)字節(jié)屏积。24是基準(zhǔn) 8 的整數(shù)倍,因此不需要填充磅甩。
最終 sizeof(struct3) 的大小為 24
其實(shí)數(shù)組寫(xiě)法很類(lèi)似下面的寫(xiě)法:
struct Struct3 {
char a;
int b0;
int b1;
double c;
}struct3;
只要調(diào)整對(duì)了數(shù)組第一個(gè)元素的offset炊林,數(shù)組后續(xù)元素自然可以對(duì)齊。
成員為struct的情況:
- 找到最大的基礎(chǔ)類(lèi)型成員 , 將其內(nèi)存長(zhǎng)度作為基準(zhǔn) (如果成員為struct卷要,基準(zhǔn)不按子struct總長(zhǎng)渣聚,而是max(子struct基準(zhǔn),剩余成員內(nèi)存長(zhǎng)度))
- 每個(gè)成員的offset僧叉,需要是成員自己類(lèi)型的整數(shù)倍 (如果成員為struct, 只需是 成員struct 基準(zhǔn)的整數(shù)倍而不是總長(zhǎng)的整數(shù)倍)
struct Struct1 {
double a; // 8
char b; // 1
int c; // 4
short d; // 2
}struct1;
struct Struct4 {
int b; // 4 // (0-3)
char c; // 1 // (4)
struct Struct1 s1; // a:8 (8 - 15) b:1 (16) c:4 (20 - 23) d:2 (24-25) (8 - 25) 18字節(jié) ->
short d; // 2 // 38 (36 - 37)
}struct4;
1. Struct1的基準(zhǔn)為8奕枝,除Struct1 s1外,Struct4最長(zhǎng)的元素是int 長(zhǎng)為4瓶堕,基準(zhǔn)為max(8隘道,4) = 8
2.
struct Struct4 {
int b; // 4 // offset:0 ,存放位置: (0-3)
char c; // 1 // offset:4捞烟,存放位置: (4)
struct Struct1 s1;
/** a: 長(zhǎng)度: 8 offset:5 -> 8 存放位置: (8 - 15)
b:長(zhǎng)度: 1 offset:16 存放位置:(16)
c: 長(zhǎng)度: 4 offset:17 -> 20 存放位置: (20 - 23)
d: 長(zhǎng)度: 2 offset:24 存放位置: (24-25)
s1 總體位置:(8 - 25) 18字節(jié) -> 填充 (8 - 31)24字節(jié)
**/
short d; // 2 // offset:32薄声,存放位置: (32 - 33)
}struct4;
3. 總體位置 (0 - 33) 長(zhǎng)度為 34,不是8的倍數(shù)题画,填充到 40
最終 sizeof(struct4) 的大小為 40
附表:
-
基礎(chǔ)數(shù)據(jù)表
2.內(nèi)存分布查看方法:
po &struct4 -> 0x00000001014cc600
x/8gx 0x00000001014cc600