一、什么是內存對齊?
內存對齊是一種在計算機內存中排列數(shù)據(jù)(表現(xiàn)為變量的地址)、訪問數(shù)據(jù)(表現(xiàn)為CPU讀取數(shù)據(jù))的一種方式。
它包含了兩種相互獨立又相互關聯(lián)的部分:基本數(shù)據(jù)對齊和結構體數(shù)據(jù)對齊 。
二、為什么要進行內存對齊?
1、平臺原因(移植原因):不是所有的硬件平臺都能訪問任意地址上的任意數(shù)據(jù)的;某些硬件平臺只能在某些地址處取某些特定類型的數(shù)據(jù),否則拋出硬件異常。
2、性能原因:數(shù)據(jù)結構(尤其是棧)應該盡可能地在自然邊界上對齊。原因在于,為了訪問未對齊的內存,處理器需要作兩次內存訪問;而對齊的內存訪問僅需要一次訪問。
說的通俗點就是方便讀取,速度快。
三、內存對齊原則:
1、數(shù)據(jù)成員對?規(guī)則:結構(struct)(或聯(lián)合(union))的數(shù)據(jù)成員,第一個數(shù)據(jù)成員放在offset為0的地方,以后每個數(shù)據(jù)成員存儲的起始位置要從該成員大小或者成員的子成員大小(只要該成員有子成員,比如說是數(shù)組,結構體等)的整數(shù)倍開始(比如int為4字節(jié),則要從4的整數(shù)倍地址開始存儲)。下面咱們用(m, n)來理解一下,其中m為內存的起始位置,n為當前成員的內存大小,m,n一定要滿足m%n==0。
2、結構體作為成員:如果一個結構里有某些結構體成員,則結構體成員要從其內部最大元素大小的整數(shù)倍地址開始存儲(struct a里存有struct b,b里有char、int 、double等元素,那b應該從8的整數(shù)倍開始存儲。)
3、收尾工作:結構體的總大小,也就是sizeof的結果,必須是其內部最大成員的整數(shù)倍,不足的要補?。
各位同學,能理解上面這些原則嗎,反正光看文字我是理解不了,沒關系,咱們是程序員,咱們可以用代碼來解釋。
四、數(shù)據(jù)成員結構體內存分析
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;
NSLog(@"結果為:%lu-%lu",sizeof(struct1),sizeof(struct2));
咱們來看下打印結果
結果為:24-16
為什么會出現(xiàn)不同的結果呢,咱們來分析一下,不過在分析代碼之前呢咱們先看下各個類型的內存大小

下面咱們來分析一下
Struct1的結果:
- 首先
Struct1中以double開始,在內存中的地址是0~7。 - 接下來是
char,char占用內存大小為1字節(jié),此時在內存中的起始地址為8,此時8%1==0表示可以從此位置開始存放char,在內存中的地址是8。 - 然后是
int,int占用內存大小為4字節(jié),此時在內存中的起始位置為9,但是現(xiàn)在9%4 != 0,所以此時只能向后移,找到一個能被4整除的數(shù),下一個能被4整除的數(shù)是12,所以此時int的起始位置為12,長度為4字節(jié),在內存中的地址是12~15。 - 最后是
short,short占用內存2字節(jié),此時內存中的起始位置為16,16%2==0成立,所以short在內存中的起始位置是16,長度為2,在內存中的地址是16~17。
由上述結果可得Struct1在內存中占用18個字節(jié),根據(jù)內存對齊第三條原則,Struct1內部最大成員為double為8字節(jié),所以Struct1最終占用的內存大小為24字節(jié)。由此可以得出下圖:Struct1內存分布圖
同理,我們再來分析一下Struct2的結果:
- 首先
Struct2中以double開始,在內存中的地址是0~7。 - 然后是
int,int占用內存大小為4字節(jié),此時在內存中的起始位置為8,8%4 == 0等式成立,所以此時int的起始位置為8,長度為4字節(jié),在內存中的地址是8~11。 - 接下來是
char,char占用內存大小為1字節(jié),此時在內存中的起始地址為12,此時12%1==0等式成立表示可以從此位置開始存放char,在內存中的地址是12。 - 最后是
short,short占用內存2字節(jié),此時內存中的起始位置為13,13%2==0等式不成立,需要向后移,找到一個能被2整除的數(shù),所以short在內存中的起始位置是14,長度為2,在內存中的地址是14~15。
有上述結果可得Struct2在內存中占用16個字節(jié),根據(jù)內存對齊原則第三條,Struct2內部最大成員為double為8字節(jié),所以Struct2最終占用的內存大小為16字節(jié)。由此可得出下圖:
Struct2內存分布圖
這就是Struct1和Struct2結果不同的原因。
由此我們可以得出結論:結構體所占內存大小與結構體內部的成員變量的順序有關。
五、嵌套結構體內存分析
struct Struct3 {
double a; //8
char b; //4
struct Struct1 c; //24
short d; //2
}struct3;
struct Struct4 {
double a; //8
char b; //1
short c; //2
struct Struct2 d; //16
}struct4;
NSLog(@"結果為:%lu-%lu",sizeof(struct3),sizeof(struct4));
咱們來看下打印結果
結果為:48-32
我們來分析下Struct3的結果:
- 首先
Struct3中以double開始,在內存中的地址是0~7。 - 接下來是
char,char占用內存大小為1字節(jié),此時在內存中的起始地址為8,此時8%1==0等式成立表示可以從此位置開始存放char,在內存中的地址是8,在內存中的地址是8。 - 然后是結構體
Struct1,由上面的結論得知Struct1的大小為24字節(jié),此時在內存中的起始地址為9,根據(jù)內存對齊原則第二條得知需從其內部最大元素大小的整數(shù)倍地址開始存儲,Struct1中最大的為double占8字節(jié),9%8 == 0不成立,所以取最近的一個能被8整除的數(shù)為16,所以Struct1在內存中的起始位置為16,長度為24,在內存中的地址是16~39。 - 最后是
short,short占用內存2字節(jié),此時內存中的起始位置為40,40%2==0等式成立,起始位置是40,長度為2,在內存中的地址是40~41。
有上述結果可得Struct3在內存中占用42個字節(jié),根據(jù)內存對齊原則,Struct3內部包括子成員Struct1內部最大成員為double為8字節(jié),所以Struct3最終占用的內存大小為48字節(jié)。由此可得出下圖:Struct3內存分布圖
我們來分析下Struct4的結果:
- 首先
Struct4中以double開始,在內存中的地址是0~7。 - 接下來是
char,char占用內存大小為1字節(jié),此時在內存中的起始地址為8,此時8%1==0等式成立表示可以從此位置開始存放char,在內存中的地址是8,在內存中的地址是8。 - 然后是
short,short占用內存2字節(jié),此時內存中的起始位置為9,9%2==0等式不成立,其后能被2整除的數(shù)為10,那么起始位置是10,長度為2,在內存中的地址是10~11。 - 最后是結構體
Struct2,由上面的結論得知Struct2的大小為16字節(jié),此時在內存中的起始地址為12,根據(jù)內存對齊原則第二條得知需從其內部最大元素大小的整數(shù)倍地址開始存儲,Struct2中最大的為double占8字節(jié),12%8 == 0不成立,所以取最近的一個能被8整除的數(shù)為16,所以Struct2在內存中的起始位置為16,長度為16,在內存中的地址是16~31。
有上述結果可得Struct4在內存中占用32個字節(jié),根據(jù)內存對齊原則,Struct4內部包括子成員Struct1內部最大成員為double為8字節(jié),所以Struct4最終占用的內存大小為32字節(jié)。由此可得出下圖:Struct4內存分布圖
以上就是我對內存對齊原則的理解,如果有不同意見的同學歡迎留言給我。



