什么是內(nèi)存對齊
先來看一個(gè)例子
struct s1 {
double a;
int b;
char c;
short d;
}s1;
struct s2 {
int a;
double b;
char c;
short d;
}s2;
printf("%lu-%lu \n", sizeof(s1), sizeof(s2));
每種數(shù)據(jù)類型的大小可參考:
按照圖計(jì)算,內(nèi)存大小應(yīng)該都為
8(double)+4(int)+1(char)+2(short)=15
,然后運(yùn)行結(jié)果如圖:可見,系統(tǒng)內(nèi)部是按照一定規(guī)則進(jìn)行內(nèi)存分配的,而這個(gè)規(guī)則就叫內(nèi)存對齊。
內(nèi)存對齊規(guī)則
1.數(shù)據(jù)成員對?規(guī)則:結(jié)構(gòu)(struct)(或聯(lián)合(union))的數(shù)據(jù)成員,第一個(gè)數(shù)據(jù)成員放在offset為0的地方状您,以后每個(gè)數(shù)據(jù)成員存儲的起始位置要從該成員大小或者成員的子成員大小(只要該成員有子成員耻讽,比如說是數(shù)組友瘤,結(jié)構(gòu)體等)的整數(shù)倍開始(比如int為4字節(jié),則要從4的整數(shù)倍地址開始存儲基公。
2.結(jié)構(gòu)體作為成員:如果一個(gè)結(jié)構(gòu)里有某些結(jié)構(gòu)體成員,則結(jié)構(gòu)體成員要從其內(nèi)部最大元素大小的整數(shù)倍地址開始存儲条篷。
3.結(jié)構(gòu)體的總大小,也就是sizeof的結(jié)果,.必須是其內(nèi)部最大成員的整數(shù)倍,不足的要補(bǔ)?需纳。
struct s1 {
double a; //8字節(jié) 0~7
int b; //4字節(jié) 8是4的倍數(shù),所以從8開始 8~11
char c; //1字節(jié) 12是1的倍數(shù), 12
short d; //2字節(jié) 13不是2的倍數(shù),14是,所以占14,15
}s1;
//總大小16字節(jié),最大成員為double,16是8的倍數(shù),所以最終結(jié)果為16
struct s2 {
int a; //4字節(jié) 0~3
double b; // 8字節(jié) 8~15
char c; //1字節(jié) 16
short d;//2字節(jié) 18~19
}s2;
//總大小20,最大成員為double,20不是8的倍數(shù),需要往上加到8*3=24,所以最終結(jié)果為24
結(jié)構(gòu)體嵌套
struct s3 {
int a; //4
struct s1 b;//最大成員double 8,從8開始 8~23
struct s2 c;//最大成員double 8, 從24開始24~47
}s3;
//總大小48,最大成員為8,最終結(jié)果為48
為什么要使用內(nèi)存對齊
因?yàn)閮?nèi)存中速度尤為重要芦倒,所以在讀取中固定了讀取大小,這樣有利于提高讀取速度不翩,而蘋果一般是16字節(jié)16字節(jié)進(jìn)行讀缺铩(為什么是16字節(jié)不是8,因?yàn)橐粋€(gè)類中包含isa占8個(gè)字節(jié)口蝠, 一個(gè)對象指針也是占8字節(jié)器钟,所以蘋果按16字節(jié)進(jìn)行讀取)
假如類的內(nèi)容占24個(gè)字節(jié)妙蔗,在進(jìn)行讀取時(shí)傲霸,第一次讀取16個(gè)字節(jié),還剩8個(gè)字節(jié)眉反,第二次讀取時(shí)昙啄,就會讀取下一個(gè)類的8個(gè)字節(jié),從而造成數(shù)據(jù)錯(cuò)誤寸五,而進(jìn)行內(nèi)存對齊后梳凛,必然是16的倍數(shù),從而讀到內(nèi)容必然在一個(gè)類中梳杏。