C++ 記憶體對齊
注:本文程式碼測試環境為win7 X64 cpu, 編譯器為gcc4.7.1 和 vs2010
記憶體對齊是編譯器為了便於CPU快速訪問而採用的一項技術
我們先從一個例子開始,對下面的類(或者結構體)
class node
{
char c;
int i;
short s;
}no;
sizeof(no)的值是多少呢,如果你的回答是7(1+4+2),那麼你應該認真閱讀下面的內容。可以在編譯器上試試,輸出的結果是12,這就是記憶體對齊的結果。
為什麼要進行記憶體對齊呢?
- 平臺原因(移植原因):不是所有的硬體平臺都能訪問任意地址上的任意資料的;某些硬體平臺只能在某些地址處取某些特定型別的資料,否則丟擲硬體異常。
- 效能原因:資料結構(尤其是棧)應該儘可能地在自然邊界上對齊。原因在於,為了訪問未對齊的記憶體,處理器需要作兩次記憶體訪問;而對齊的記憶體訪問僅需要一次訪問。 本文地址
編譯器一般按照幾個位元組對齊呢?本文中兩個編譯器預設按照類中最大型別長度來對齊,我麼也可以使用語句#pragma pack(i)(i = 1,2,4,8,16)來設定對齊位元組數目,vs還可以在專案屬性-配置屬性-c/c++-程式碼生成-結構成員對齊設定。
對齊規則如下:
- 如果設定了記憶體對齊為 i 位元組,類中最大成員對齊位元組數為j,那麼整體對齊位元組n = min(i, j) (某個成員的對齊位元組數定義:如果該成員是c++自帶型別如int、char、double等,那麼其對齊位元組數=該型別在記憶體中所佔的位元組數;如果該成員是自定義型別如某個class或者struct,那個它的對齊位元組數 = 該型別內最大的成員對齊位元組數《詳見例項4》)
- 每個成員對齊規則:類中第一個資料成員放在offset為0的位置;對於其他的資料成員(假設該資料成員對齊位元組數為k),他們放置的起始位置offset應該是 min(k, n) 的整數倍
- 整體對齊規則:最後整個類的大小應該是n的整數倍
- 當設定的對齊位元組數大於類中最大成員對齊位元組數時,這個設定實際上不產生任何效果(例項2);當設定對齊位元組數為1時,類的大小就是簡單的把所有成員大小相加
我們通過以下幾個例項來分析
例項1:(沒有指定對齊位元組,則n = 最大成員(int i)的大小4)
class node
{
char c; //放在位置0,位置區間[0]
int i; //4 = n, 那麼放置起始位置應該是4的倍數,即4,位置區間為[4~7]
short s; //2 < n,那麼放置起始位置應該是2的倍數,即8,位置區間為[8~9]
}
此時成員共佔用[0~9]10個位元組,還要整體對齊,大小應該是4的倍數,即12
例項2:(假設指定對齊位元組為8,那麼n = min(8,4) = 4)
class node
{
int i; //放在位置0,位置區間[0~3]
char c; //1 < n, 那麼放置起始位置應該是1的倍數,即4,位置區間為[4]
short s; //2 < n,那麼放置起始位置應該是2的倍數,即6,位置區間為[6~7]
}
成員共佔據[0~7]8個位元組,剛好是4的倍數,因此大小是8
例項3:(假設指定對齊位元組是2,則n = min(2,4) = 2)
class node
{
char c; //放在位置0,位置區間[0]
int i; //4 > n, 那麼放置起始位置應該是2的倍數,即2,位置區間為[2~5]
short s; //2 = n,那麼放置起始位置應該是2的倍數,即6,位置區間為[6~7]
}
此時成員共佔用[0~7]8個位元組,剛好是4的倍數,因此大小是8
例項4:(按照預設設定)
class temp
{
char c;
int i;
short s1;
};
由例項1可知,預設對齊情況下,temp的大小是12,temp的對齊位元組數是:三個成員取最大的,即為4;
對於node,n = 其三個成員對齊位元組數取最大,即等於t的對齊位元組數,也就是 4。
class node
{
char c; //放在位置0,位置區間[0]
temp t; //4(temp的對齊位元組數) = n, 那麼放置起始位置應該是4的倍數,即4,位置區間為[4~15]
short s; //2 < n,那麼放置起始位置應該是2的倍數,即16,位置區間為[16~17]
}
此時成員共佔用[0~17]18個位元組,還要整體對齊,大小應該是4的倍數,因此大小是20
例項5:(默然設定)
對於node,n = 其三個成員對齊位元組數取最大,即等於d的對齊位元組數,也就是 8。
class node
{
temp t; //放在位置0,位置區間[0~11]
double d; //8(temp的對齊位元組數) = n, 那麼放置起始位置應該是8的倍數,即16,位置區間為[16~23]
short s; //2 < n,那麼放置起始位置應該是2的倍數,即24,位置區間為[24~25]
}
此時成員共佔用[0~25]26個位元組,還要整體對齊,大小應該是8的倍數,因此大小是32.
類繼承時的記憶體對齊
考慮如下類
class A
{
int i;
char c1;
}
class B:public A
{
char c2;
}
class C:public B
{
char c3;
}
sizeof(C)結果是多少呢,gcc和vs給出了不同的結果,分別是8、16
gcc中:C相當於把所有成員i、c1、c2、c3當作是在一個class內部,(先繼承後對齊)
vs中:對於A,對齊後其大小是8;對於B,c2加上對齊後的A的大小是9,對齊後就是12;對於C,c3加上對齊後的B大小是13,再對齊就是16 (先對齊後繼承)
關於c++物件繼承後的記憶體佈局,更詳細的分析可以《深度探索參考c++物件模型》第三章
參考資料:
zhyjunfov的ChinaUnix部落格:gcc的記憶體對齊
【版權宣告】轉載請註明出處:http://www.cnblogs.com/TenosDoIt/p/3590491.html
相關文章
- C++ struct結構體記憶體對齊C++Struct結構體記憶體
- C/C++記憶體對齊原則C++記憶體
- C/C++記憶體對齊詳解C++記憶體
- 記憶體對齊記憶體
- GO 記憶體對齊Go記憶體
- 理解記憶體對齊記憶體
- 結構體記憶體對齊結構體記憶體
- C# 記憶體對齊C#記憶體
- iOS 記憶體位元組對齊iOS記憶體
- C語言記憶體對齊C語言記憶體
- c 結構體記憶體對齊詳解結構體記憶體
- iOS探索 記憶體對齊&malloc原始碼iOS記憶體原始碼
- Netty原始碼解析 -- 記憶體對齊類SizeClassesNetty原始碼記憶體
- struct結構體大小的計算(記憶體對齊)Struct結構體記憶體
- Dig101:Go 之聊聊 struct 的記憶體對齊GoStruct記憶體
- 記憶體對齊巨集定義的簡明解釋記憶體
- C結構體中資料的記憶體對齊問題結構體記憶體
- 從 CPU 角度理解 Go 中的結構體記憶體對齊Go結構體記憶體
- netcore高階知識點,記憶體對齊,原理與示例NetCore記憶體
- Go plan9 彙編:記憶體對齊和遞迴Go記憶體遞迴
- C++記憶體管理C++記憶體
- 居然這就是C++記憶體對映檔案?!C++記憶體
- C/C++結構體對齊測試C++結構體
- C++記憶體掃描C++記憶體
- C++記憶體管理剖析C++記憶體
- C++ 位元組對齊C++
- Go高效能程式設計-瞭解記憶體對齊以及Go中的型別如何對齊保證Go程式設計記憶體型別
- 【C++】C++的位元組對齊C++
- C++記憶體管理:簡易記憶體池的實現C++記憶體
- Go 的記憶體對齊和指標運算詳解和實踐Go記憶體指標
- 【轉載】ARM嵌入式系統為什麼要做記憶體對齊記憶體
- C++動態記憶體分配C++記憶體
- C++手寫記憶體池C++記憶體
- c/c++ 位元組對齊C++
- #pragma pack記憶體對齊的實現以及相關微軟面試題記憶體微軟面試題
- 遊戲記憶體對比普通記憶體區別 遊戲記憶體和普通記憶體相差大嗎?遊戲記憶體
- C++記憶體模型實踐探索C++記憶體模型
- 探索 Go 語言中的記憶體對齊:為什麼結構體大小會有所不同?Go記憶體結構體
- 從C++看C#託管記憶體與非託管記憶體C++C#記憶體