內存對齊小解

本次試驗是在32位系統下進行的。
 
1、什麼是內存對齊

       現代計算機中內存空間都是按照byte劃分的,從理論上講彷佛對任何類型的變量的訪問能夠從任何地址開始,但實際狀況是在訪問特定變量的時候常常在特定的內存地址訪問,這就須要各種型數據按照必定的規則在空間上排列,而不是順序的一個接一個的排放,這就是對齊。數據結構

       爲何要了解內存對齊:各個硬件平臺對存儲空間的處理上有很大的不一樣。一些平臺對某些特定類型的數據只能從某些特定地址開始存取。其餘平臺可能沒有這種狀況,可是最多見的是若是不按照適合其平臺要求對數據存放進行對齊,會在存取效率上帶來損失。好比有些平臺每次讀都是從偶地址開始,若是一個int型(假設爲32位系統)若是存放在偶地址開始的地方,那麼一個讀週期就能夠讀出,而若是存放在奇地址開始的地方,就可能會須要2個讀週期,並對兩次讀出的結果的高低字節進行拼湊才能獲得該int數據。顯然在讀取效率上降低不少。這也是空間和時間的博弈。性能

  一般咱們不須要去主動進行內存對齊的操做,編譯器會自動爲咱們選擇最優的對齊規則方式,合理利用空間節省程序運行的時間,但如果咱們能瞭解這種規則,對於咱們編寫程序仍是會有很大的幫助的。spa

2、對齊內存規則
  1.第一個成員在與結構體變量偏移量爲0的地址處。
  2.其餘成員變量要對齊到對齊數(編譯器默認的一個對齊數與該成員大小的較小值)的整數倍的地址處。
  3.結構體總大小爲最大對齊數(除了第一個成員每一個成員變量都有一個對齊數)的整數倍。
  4.若是嵌套告終構體的狀況,嵌套的結構體對齊到本身的最大對齊數的整數倍處,結構體的總體大小就是全部最大對齊數(含嵌套結構體的對齊數)的整數倍。
 
3、實例解釋
 
要想要看出數據的對齊方式,首先你就得明白各類數據類型在各類操做系統下所佔字節的大小。
咱們來看一下在32位系統下各類參數類型所佔字節的大小:
接着咱們用幾個例子來說解對齊規則:
(1)
首先咱們用一字節對齊的方式來檢驗咱們以前所說的類型所佔字節大小:
 1 #pragma pack(1)//讓編譯器對此結構體做字節對齊
 2 struct A
 3 {
 4         char a;//  1
 5         int b;//   4
 6         short c;// 2
 7         long d;//  4
 8         float e;// 4
 9 };
10 #pragma pack()//取消字節對齊,回覆默認字節對齊
11 int main()
12 {
13         struct A a;
14         printf("%d\n",sizeof(a));
15         return 0;
16 }
若是沒有字節對齊(或者爲一字節對齊方式),按照咱們以前的計算方式,1+4+2+4+4=15,所佔字節大小應該爲15。
程序運行:
 
(2)咱們取消以前的設置,直接使用默認對齊數對齊。
 1 #include <stdio.h>
 2 //#pragma pack(1)//讓編譯器對此結構體做字節對齊
 3 struct A
 4 {
 5         char a;//  1
 6         int b;//   4
 7         short c;// 2
 8         long d;//  4
 9         float e;// 4
10 };
11 //#pragma pack()//取消字節對齊,回覆默認字節對齊
12 int main()
13 {
14         struct A a;
15         printf("%d\n",sizeof(a));
16         return 0;
17 }

程序運行:操作系統

由上圖能夠看到,明明是同樣的程序,只不過取消了1字節對齊,就由原來的佔15字節變成了佔20字節,這就是字節對齊的緣由。
咱們用一張圖來解釋:
  第一個成員char一開始佔用的是0偏移處,佔用一個字節位,但因爲是4字節對齊,且第二個成員int佔用的字節位4,在4字節對齊的規則下,char後面只有三個字節空位,不足以放下,因此在三偏移處另開一個空存放,第三個成員short佔用2字節,能夠放入,第四個成員long和第五個成員float依照前面的規則正好存放20個字節,20個字節正好爲這個結構體的最大對齊數的整數倍,因此這個結構體佔用空間爲20字節。
 
(3)前面咱們說的都是恰好的狀況,有些朋友可能仍是不能很好的理解這個規則,咱們再舉幾個例子:
 1 #include <stdio.h>
 2 //#pragma pack(1)//讓編譯器對此結構體做字節對齊
 3 struct A
 4 {
 5         char a;//  1
 6         int b;//   4
 7         short c;// 2
 8         //long d;//  4
 9         //float e;// 4
10 };
11 //#pragma pack()//取消字節對齊,回覆默認字節對齊
12 int main()
13 {
14         struct A a;
15         printf("%d\n",sizeof(a));
16         return 0;
17 }

程序運行:code

  char、int、short按一字節方式爲7,可是結構體對齊以後爲12,按照咱們在(2)中將的方式:char佔0偏移處,一字節;int在插入以後放不下,因此另起一個整數倍空間,在3偏移處,佔4字節;short在7偏移處,佔2字節。總共佔10字節,但按照咱們以前講的,整個結構體的大小應該爲最大偏移數的整數倍,因此最小整數倍應該爲12,因此整個結構體佔12字節。
 
(4)若是不信,咱們能夠在來變化一下結構體內數據驗證
 1 #include <stdio.h>
 2 //#pragma pack(1)//讓編譯器對此結構體做字節對齊
 3 struct A
 4 {
 5         char a;//  1
 6         //int b;//   4
 7         short c;// 2
 8         long d;//  4
 9         char g;//  1
10         //float e;// 4
11 };
12 //#pragma pack()//取消字節對齊,回覆默認字節對齊
13 int main()
14 {
15         struct A a;
16         printf("%d\n",sizeof(a));
17         return 0;
18 }

程序運行:blog

  char在0偏移處,佔一字節,short爲2字節,在最大偏移數的範圍內能存下,因此在1偏移處佔2字節,long在3偏移處佔4字節,char在7偏移處佔1字節,總共佔9字節,按照對齊規則,總大小應該爲4的整數倍,因此總大小爲12。
 
 
4、對齊緣由
  1.平臺緣由(移植緣由):不是全部的硬件平臺都能訪問任意地址上的任意數據的;某些硬件平臺只能在某些地址處取某些特定類型的數據,不然拋出硬件異常。
  2.性能緣由:數據結構(尤爲是棧)應該儘量地訪問在天然邊界上對齊。緣由在於,爲了訪問未對齊的內存,處理器須要做兩次內存訪問;而對齊的內存訪問僅須要一次訪問。
 
5、內存對齊的好處
你知道了內存對齊的規則那麼咱們在編寫程序的時候就能編寫出更加有效高效的程序。
用一個例子來簡單的解釋一下:
 1 #include <stdio.h>
 2 
 3 struct A
 4 {
 5         char a;
 6         int b;
 7         short c;
 8 };
 9 struct B
10 {
11         char a;
12         short b;
13         int c;
14 };
15 int main()
16 {
17         struct A a;
18         struct B b;
19         printf("%d\n",sizeof(a));
20         printf("%d\n",sizeof(b));
21         return 0;
22 }

程序運行:內存

結構體內成員都同樣可是排列方式不同,結構體的佔用空間不同。
用兩張圖就能夠簡單解釋:
相關文章
相關標籤/搜索