記憶體對齊巨集定義的簡明解釋

AD_milk 發表於 2022-01-28

我想你一定看到過類似這樣的程式碼

((size) + ALIGNMENT - 1) & ~(ALIGNMENT-1)) 

看字大致意思是要記憶體對齊,但也不明白為為什麼寫成這樣?

在計算機中主存按一個傳送單位(32/64/128位)進行存取,按位元組編址

如果傳送單位為32位,也就意味著第0-3位元組能同時讀寫,第4-7位元組能同時讀寫。

如果需要讀寫3-6位元組的資料,則計算機需要分別讀兩次(0-3 4-7),無法直接讀取3-6位元組的資料

直觀感受的記憶體與處理器眼中的記憶體

總而言之,對齊的粒度一定是2的n次方這種形式,在二進位制表示下一定會長成這樣(1後面跟著n個0):

000100...00

假設我們要分配的變數需要size大小的空間。

要想資料不出現橫跨兩個傳送單位的尷尬情況,我們必須按照傳送單位的整數倍去分配記憶體。

size & ~(ALIGNMENT - 1)

這裡的ALIGNMENT根據自己的需求和硬體平臺變動

現在先假定有宣告

#define ALIGNMENT 4 // 4位元組對齊

(ALIGNMENT - 1)這一塊為0011,取反之後為1100,相當於掩碼,最後兩位會被置為0。這樣就得出來的數一定是ALIGNMENT(本例中是4)的整數倍

現在我們已經知道了~(ALIGNMENT-1)是為了取整

請你算一下如果size=3按照size & ~(ALIGNMENT - 1)來算的話記憶體怎麼分配

0011 & 1100 = 0

這顯然是錯的,所以我們得加上 ALIGNMENT - 1來確保當size<ALIGNMENT時也能得到正確結果。

為什麼不是加上ALIGNMENT呢?

  • ~(ALIGNMENT - 1)是把低n位清零,我們將低n位先填滿這樣當size>0時會進行向上取整

  • 如果是加ALIGNMENT,當size=ALIGNMENT時我們會多申請一個記憶體單元

所以最後的表示式為:

((size) + ALIGNMENT - 1) & ~(ALIGNMENT-1)) 
size size & ~(ALIGNMENT - 1) ((size) + ALIGNMENT - 1) & ~(ALIGNMENT-1))
0 0 0
3 0(錯誤) 4
4 8(多分配了不必要的記憶體) 4