任何k位元組的基本物件的位址必須是k的倍數。基本物件:int、double、long、short等基本資料型別,不包括struct、union、class。
struct
s1;
設s1的首位址為xp,對於s1來說,最大的基本元素為int,所以**xp**必須是4的整數倍,稱s1滿足4位元組對齊。
(1)結構體內部任何k位元組的基本物件相對於結構體首位址的偏移,必須是k的整數倍。
struct
s1;
顯然,j的偏移5並不是j的長度(int 4位元組)的整數倍。所以需要在char c後面補充3個位元組進行對齊,對齊後的結構體如下:
struct
s1;
至此,結構體滿足內部所有基本物件的偏移都是物件大小的整數倍。
(2)在滿足第乙個要求後,只要滿足s1首位址為s1中最大基本物件長度的整數倍,即可滿足位元組對齊的要求。
對於s1中的物件「j」,其相對於s1的偏移為8,可以被「j」的大小4整除,所以只要s1的首位址可以被4整除,那「j」的位址一定能被4整除;相反,s1的首位址不能被4整除,那「j」的位址也一定不能被4整除。
此外,能被4整除就一定能被2整除,也一定能被1整除。所以只要結構體首位址能被其中最大物件的長度整除,那就能被所有物件的長度整除。
隱含條件:
至此,考慮另外一種情況:
struct
s2;
當前結構體內部元素的偏移滿足條件(1),看似沒什麼問題。但是,當定義變數s2 a[2];
時可以發現如果a的位址為xs,那麼a[1]的位址為xs + 9,顯然不能被4整除,違背了條件(2)。所以第條件(2)有乙個隱含條件:結構體的長度要能被其中最大物件的長度整除。於是需要在s2的物件「c」後面新增3個位元組,使s2的總長度變為12,如下所示:
struct
s2;
在c語言中,當使用了#pragma pack n後(不使用時n為預設值)位元組對齊的規則為:
任何k位元組基本物件的位址必須是k和n之間較小者的整數倍。例如:
#
pragma
pack 2
structs1;
#pragma
pack()
測試用例:#
上圖展示了乙個記憶體模組的基本思想。模組有8個64mbit(注意是mbit不是mbyte)的8m*8的dram晶元,總容量64mb。要取出位址為a處的乙個字(這裡指的機器字長),記憶體控制器將a轉換成乙個supercell位址(i,j),並將它傳送到記憶體模組,然後記憶體模組再將i和j廣播到每個dram。作為響應,每個dram輸出它的(i,j)對應的supercell的8位內容。記憶體模組收集這些輸出,並把他們合併成乙個64位的字,再返回給記憶體控制器。
從上面的描述中可以發現幾個要點:
假設我們現在需要從0x00處取8個位元組的資料,即我們需要取出位於0x00-0x07的資料。根據上面的描述,我們不難推斷,0x00位於dram0,0x01位於dram1,0x02位於dram2以此類推。不難看出在這種情況下只需要對記憶體進行一次讀操作就可以取出全部8位元組資料。
情況1:
現在我們考慮另一種情況,需要從0x01處取4個位元組的資料,即我們需要取出位於0x01-0x04的資料。在這種情況下,cpu會獲取0x00-0x07的8個位元組資料,然後從中讀取0x01-0x04,這種情況也只需讀一次記憶體。
情況2:
我們再考慮一種情況,需要從0x01處取8個位元組的資料,即我們需要取出位於0x01-0x08的資料。在這種情況下cpu需要做如下操作:
可以看出在這種情況下cpu不光需要讀兩次記憶體,還需要做額外的「組合」操作。效能會大大降低,並且某些cpu根本不支援這樣的操作。這就是為什麼需要要求任何k位元組的基本物件的位址必須是k的倍數,也就是位元組對齊。
現代的計算機體系結構在cpu和記憶體之間還存在快取記憶體。當cpu需要從記憶體中獲取資料時,會首先訪問快取記憶體,如果快取記憶體中有相應資料,則從快取中直接讀取,否則需要首先將資料從記憶體中載入到快取中。那麼當資料是如何從記憶體載入到快取中的?是否也涉及位元組對齊問題呢?
上圖展示了快取記憶體的結構,乙個快取記憶體有s個快取記憶體組,每個組包含e個快取記憶體行,每個行含有b位元組的資料塊。
快取記憶體一次從記憶體讀取b個位元組的資料,通常b和機器字長相等(至少core i7 l1~l3快取的資料塊大小都是64位元組)。可以簡單的理解為一次讀乙個快取行(快取行中除了資料塊之外,還有vaild和tag)
cpu是按照一定規則將記憶體中的資料載入到對應快取行的,對於起始位址為a的m位位址,會被解析成以下幾個部分:
b由資料塊大小決定:b = 2b
s由快取記憶體組個數決定:s = 2s
t = m - (s + b)
我們不難得出乙個結論:
如果機器字長為64位,即8位元組,那麼位於0x00-0x07的資料和位於0x08-0x10的資料絕對不會被載入到同乙個快取行!
對於上面的情況2,如果我們需要從0x01處取8個位元組的資料,即我們需要取出位於0x01-0x08的資料,那麼即便是可以直接從快取記憶體中獲取,也需要訪問兩個快取行,並且同樣需要合併操作!可見位元組對齊是多麼的重要!
位元組對齊詳解
現代計算機中記憶體空間都是按照byte劃分的,從理論上講似乎對任何型別的變數的訪問可以從任何位址開始,但實際情況是在訪問特定型別變數的時候經常在特 定的記憶體位址訪問,這就需要各種型別資料按照一定的規則在空間上排列,而不是順序的乙個接乙個的排放,這就是對齊。對齊的作用和原因 各個硬體平台對儲存空間的...
位元組對齊詳解
現代計算機中記憶體空間都是按照byte劃分的,從理論上講似乎對任何型別的變數的訪問可以從任何位址開始,但實際情況是在訪問特定型別變數的時候經常在特 定的記憶體位址訪問,這就需要各種型別資料按照一定的規則在空間上排列,而不是順序的乙個接乙個的排放,這就是對齊。對齊的作用和原因 各個硬體平台對儲存空間的...
位元組對齊詳解
現代計算機中記憶體空間都是按照byte劃分的,從理論上講似乎對任何型別的變數的訪問可以從任何位址開始,但實際情況是在訪問特定型別變數的時候經常在特 定的記憶體位址訪問,這就需要各種型別資料按照一定的規則在空間上排列,而不是順序的乙個接乙個的排放,這就是對齊。對齊的作用和原因 各個硬體平台對儲存空間的...