您當前的位置:首頁 > 體育

大話C++之:記憶體對齊

作者:由 馮文斌 發表于 體育時間:2020-08-05

在使用sizeof()計算結構體和class大小的時候,往往很多時候計算出來並不是我們想要的結果。最近在使用的時候就特別想了解它內在的原理,搞懂它的本質。

看一下下面這個例子:

struct

Struct

{

char

a

int

i

};

問題是:這個結構體大小是多少?

很多人回答可能是5個位元組。分析結構體的組成是:char佔1個字,int佔4個位元組。1+4=5,沒錯吧?

其實這個答案應該是:不確定。因為它給的條件不能夠得出一個確定的答案。

開啟VS 2017,64位程式執行一下,得出的結果是8。

既然它不是簡單的把成員大小簡單累加,想必它肯定是有一套規則,那是什麼規則呢?那就是記憶體對齊

(what)什麼記憶體對齊(Data alignment)?

百度百科的定義:編譯器為程式中的每個“資料單元”安排在適當的位置上。

我的理解是按照一定的規則把它的位置排好,排列得有規有矩,方便計算機讀取。

(why)為什麼要使用記憶體對齊

為了效能。為什麼記憶體對齊為提高效能呢?舉個例子,例如把4個位元組從地址1寫入到暫存器中。首先從前4個位元組中讀取3個節字,再從後面4個位元組中讀了1個字,最後放在暫存器中合併在一齊。讀取一個數據到暫存器中消耗了這麼多步驟,對於CPU效能來說是挺大的負擔。如果是位元組對齊了,從0開始連續讀取4個字,暫存器剛好也是4個位元組,只需要一次讀寫即可,大大提高了讀取效率。

大話C++之:記憶體對齊

大話C++之:記憶體對齊

3。 (how)記憶體對齊是如何工作的

想想我們平時要把物品整理對齊的時候,一般都有參照物或對齊的標準。如果把箱子排好,是一個個緊密對齊排列呢,還是間隔排列呢,這個標準會影響排列後使用的空間。

對於記憶體對齊,同樣也是有一個參考標準。編譯器中提供了#pragma pack(n)來設定變數以n位元組對齊方式,n即為對齊的標準。

VS 2017 64bit的位元組對齊變數為16,在程式碼中插入:#pragma pack(show),就可以檢視當前環境的變數值。

有了這個標準,還需要的是被排列的物件:欄位型別。

拿回箱子排列的例子來說,可能每一個箱子的大小不一樣,有些是短一點,有些是長一點,可能排列的位置也有不一樣。

箱子大小就如成員變數,每一個變數有自己的大小。

現在來看一步步分解,系統是如何把位置給安排得明明白白的。

例如這個

struct

Struct

{

char

a

int

i

};

每一塊記憶體記憶體是從0開始偏移的,第一個欄位直接安排下去。

第一個欄位char,偏移量(offset)為0,佔用空間1個位元組,結束位置為1;

大話C++之:記憶體對齊

關鍵一步來了,如何安排int位元組呢?

int的大小是4 bytes,位元組對齊變數為16 bytes。比較兩者間選擇小的一個,此時4 bytes作為偏移參考量X。

從當前偏移量1開始,尋找偏移參考量X最小的倍數位置。4的倍數可以是:4,8,12,16等等,當前最小的為4。然而1,2,3的位置空了,需要填充,從第4個byte開始連續4個byte為int的空間。

此時8個位元組的排布為:a——-iiii;

畫重點:char型佔用空間為1 byte,則其起始位置必須可被1整除。int為4 bytes,其起始位置必須是可以被4整除。

大話C++之:記憶體對齊

記憶體對齊的過程如上,影響同一個結構體的記憶體佈局的關鍵是:以多少位元組來對齊,如上面所說的n。最開始的例子,實際上可以透過設定n為1,可以得到size為5。

回顧一下最開始的問題,缺少一個指定變數n的條件,故不能確定大小是多少。

標簽: 對齊  位元組  記憶體  int  位置