首先由乙個程式引入話題:
程式的輸出結果為:
sizeof(st1) is 12
sizeof(st2) is 8
問題出來了,這兩個一樣的結構體,為什麼sizeof的時候大小不一樣呢?
對於大多數的程式設計師來說,記憶體對齊基本上是透明的,這是編譯器該幹的活,編譯器為程式中的每個資料單元安排在合適的位置上,從而導致了相同的變數,不同宣告順序的結構體大小的不同。
那麼編譯器為什麼要進行記憶體對齊呢?程式1中結構體按常理來理解sizeof(st1)和sizeof(st2)結果都應該是7,4(int) + 2(short) + 1(char) = 7 。經過記憶體對齊後,結構體的空間反而增大了。
在解釋記憶體對齊的作用前,先來看下記憶體對齊的規則:
1、 對於結構的各個成員,第乙個成員位於偏移為0的位置,以後每個資料成員的偏移量必須是min(#pragma pack()指定的數,這個資料成員的自身長度) 的倍數。
2、 在資料成員完成各自對齊之後,結構(或聯合)本身也要進行對齊,對齊將按照#pragma pack指定的數值和結構(或聯合)最大資料成員長度中,比較小的那個進行。
#pragma pack(n) 表示設定為n位元組對齊。 vc6預設8位元組對齊
以程式1為例解釋對齊的規則 :
st1 :char佔乙個位元組,起始偏移為0 ,int 佔4個位元組,min(#pragma pack()指定的數,這個資料成員的自身長度) = 4(vc6預設8位元組對齊),所以int按4位元組對齊,起始偏移必須為4的倍數,所以起始偏移為4,在char後編譯器會新增3個位元組的額外位元組,不存放任意資料。short佔2個位元組,按2位元組對齊,起始偏移為8,正好是2的倍數,無須新增額外位元組。到此規則1的資料成員對齊結束,此時的記憶體狀態為:
o***|oooo|oo
0123 4567 89 (位址)
(x表示額外新增的位元組)
共佔10個位元組。還要繼續進行結構本身的對齊,對齊將按照#pragma pack指定的數值和結構(或聯合)最大資料成員長度中,比較小的那個進行,st1結構中最大資料成員長度為int,佔4位元組,而預設的#pragma pack 指定的值為8,所以結果本身按照4位元組對齊,結構總大小必須為4的倍數,需新增2個額外位元組使結構的總大小為12 。此時的記憶體狀態為:
o***|oooo|ooxx
0123 4567 89ab (位址)
到此記憶體對齊結束。st1占用了12個位元組而非7個位元組。
st2 的對齊方法和st1相同,讀者可自己完成。
記憶體對齊的主要作用是:
1、 平台原因(移植原因):不是所有的硬體平台都能訪問任意位址上的任意資料的;某些硬體平台只能在某些位址處取某些特定型別的資料,否則丟擲硬體異常。
2、 效能原因:經過記憶體對齊後,cpu的記憶體訪問速度大大提公升。具體原因稍後解釋。
圖一:這是普通程式設計師心目中的記憶體印象,由乙個個的位元組組成,而cpu並不是這麼看待的。
圖二:cpu把記憶體當成是一塊一塊的,塊的大小可以是2,4,8,16位元組大小,因此cpu在讀取記憶體時是一塊一塊進行讀取的。塊大小成為memory access granularity(粒度) 本人把它翻譯為「記憶體讀取粒度」 。
假設cpu要讀取乙個int型4位元組大小的資料到暫存器中,分兩種情況討論:
1、資料從0位元組開始
2、資料從1位元組開始
再次假設記憶體讀取粒度為4。
圖三:當該資料是從0位元組開始時,很cpu只需讀取記憶體一次即可把這4位元組的資料完全讀取到暫存器中。
當該資料是從1位元組開始時,問題變的有些複雜,此時該int型資料不是位於記憶體讀取邊界上,這就是一類記憶體未對齊的資料。
圖四:此時cpu先訪問一次記憶體,讀取0—3位元組的資料進暫存器,並再次讀取4—5位元組的資料進暫存器,接著把0位元組和6,7,8位元組的資料剔除,最後合併1,2,3,4位元組的資料進暫存器。對乙個記憶體未對齊的資料進行了這麼多額外的操作,大大降低了cpu效能。
這還屬於樂觀情況了,上文提到記憶體對齊的作用之一為平台的移植原因,因為以上操作只有有部分cpu肯幹,其他一部分cpu遇到未對齊邊界就直接罷工了。
1 //環境:vc6 + windows sp2
2 //程式1
3 #include
4 5 using namespace std;
6 7 struct st1
8 ;13
14 struct st2
15 ;
20 21 int main()
22
記憶體對齊詳解
首先由乙個程式引入話題 1 環境 vc6 windows sp2 2 程式1 3 include 4 5 using namespace std 6 7 struct st1 8 13 14 struct st2 15 20 21 int main 22 23 cout sizeof st1 is ...
記憶體對齊詳解
一 為什麼會有c 記憶體對齊 以下內容節選自 intel architecture 32 manual 為了提高程式的效能,資料結構 尤其是棧 應該盡可能地在自然邊界上對齊。原因在於,為了訪問未對齊的記憶體,處理器需要作兩次記憶體訪問 然而,對齊的記憶體訪問僅需要一次訪問。乙個字或雙字運算元跨越了4...
C 記憶體對齊詳解
最近看各公司筆試和面試的試題,不少是關於c 記憶體對齊方面的。這個問題我以前也模模糊糊的了解一些,但總是不甚清楚。這次費了很大勁,終於算是搞明白了。整理出來,和大家分享一下。這一切要從機器字長和儲存字長說起。機器字長是cpu每次處理的二進位制的位數 儲存字長是記憶體中乙個儲存單元的包含二進位制位數,...