為什麼要記憶體對齊?

2021-10-23 12:33:48 字數 2391 閱讀 2701

cpu訪問非對齊的記憶體時為何需要多次讀取再拼接

首先簡單說一下何為記憶體對齊。

例如,當cpu需要取4個連續的位元組時,若記憶體起始位置的位址可以被4整除,那麼我們稱其對齊訪問。

反之,則為未對齊訪問。比如從位址0xf1取4位元組就是非對齊(位址)訪問。

簡單的看來,對於乙個資料匯流排寬度為32位的cpu,它一次擁有取出四位元組資料的能力,理論上cpu應該是可以從任意的記憶體位址取四個連續位元組的,而且是否對齊硬體的設計是相同的(如果記憶體和cpu都是位元組組織的話,那麼記憶體應當可以返回任意位址開始連續的四位元組,cpu處理起來也沒有任何差異)。

然而,很多cpu並不支援非對齊的記憶體訪問,甚至在訪問的時候會發生例外(例如arm架構的某些cpu)!而某些複雜指令集的cpu(比如x86架構),可以完成非對齊的記憶體訪問,然而cpu也不是一次性讀出四個位元組,而是採取多次讀取對齊的記憶體,然後進行資料拼接,從而實現非對齊資料訪問的。如下圖:

如果我們的資料存於記憶體的2-5中,在讀取時實際上是先讀取0-3,再讀取4-7位元組,再分別將2-3位元組和4-5位元組合併,最後得到所需的四位元組資料。

那麼為什麼cpu不直接讀取2-5,而是要麼不提供支援,要麼甚至不惜花大力氣執行多次訪問再拼接訪問非對齊的記憶體呢(如此訪問一則增加訪問時間,二則增加電路的複雜性)?這背後一定有它的原因!

經過一番網際網路搜尋,但是在國內只能找到為什麼寫程式的時候要對齊的解釋(因為cpu要麼不支援,要麼訪問效率下降),然後是如何實現對齊。沒有一篇文章從硬體原理上去分析為何訪問非對齊記憶體如此麻煩。

實際上,訪問非對齊記憶體並沒有我們想象的那麼「簡單」,例如,在乙個常見的pc上,記憶體實際上是有多個記憶體晶元共同組成的(也就是記憶體條上那些黑色的記憶體顆粒)

這意味記憶體實際上並不是完全以byte形式組織的,而是以偏移量(offset)來給出具體位址的。記憶體晶元更像是矩陣的列,而偏移量像是矩陣的行,每次cpu訪問記憶體都需要給出行,然後訪問這一行,這一行的的每個資料都儲存在單個儲存晶元上。

這樣當我們採用對齊的位址訪問時,比如從0x00開始訪問四位元組,顯然四個位元組儲存於4個晶元,而且他們都有同樣的偏移量(offset),行數,這時我們就能一次獲得所需的資料。

但是當從0x01(第二個晶元)開始讀取4位元組呢?此時前三個位元組也是按順序分別儲存在1-3晶元中的,而且偏移量都是0,但是第四個位元組卻儲存在偏移量為1的晶元0中(另起一行)。

在訪問記憶體時,cpu需要給出偏移量offset,而傳送偏移量的匯流排寬度大約是40位(64bit環境下),通常這樣的匯流排只有乙個。

這意味著在一次記憶體訪問週期內我們只能讀取乙個結果。

當然,要想一次讀取兩個offset的內容也不是不能實現,你可以增加用於傳送位址的bus數量。對於乙個64位的cpu,如果你希望在乙個訪問週期內讀取未對齊的記憶體,你需要增加到8根匯流排。這意味著需要增加接近300個io。而通常cpu的管腳數量在700-2000之間,在這基礎之上增加300將會是乙個很大的改動。換句話說,就是會大大增加硬體的複雜程度。

同時,記憶體訪問訊號的頻率是非常高的,增加的匯流排也會造成額外的雜訊干擾。

當然,還有一種方法。由於非對齊訪問最多也就訪問兩個不同的offset,而且這兩個offset總是連續,我們可以再給記憶體內部加一根額外的線,這樣就可以同時返回offset和offset+1兩個偏移量上的資料了。

但是,這樣意味著晶元內多了一些額外的加法器(用於給offset加一,得到下乙個偏移量),所有的讀操作都會在讀取前增加乙個計算操作。

這一步會降低記憶體的時鐘。於是乎,我們可能為了千分之一概率出現的非對齊訪問,增加了99.9%的對齊訪問的訪問延時。顯然這並不是乙個明智的選擇。

因此,cpu不支援,或者通過兩次讀取來實現非對齊訪問也就有理有據了。

當然,訪問非對齊的資料還存在乙個問題:cache

通常來說,cache是和offset相關聯的,不同的offset被不同的cache line快取,因此,訪問非對齊的資料也意味著多次的cache讀取,同樣會降低效率。

綜上所述,這些也基本上是訪問非對齊記憶體需要多次讀取的原因了。

參考資料:

為什麼要記憶體對齊

當我們聽到 記憶體對齊 這個概念時,從字面意思來看,很容易理解。那就是讓記憶體按一定規則對齊。當然 就會有人說 你這不是廢話 現在我就來說一說為什麼要記憶體對齊以及怎麼個對齊法 如何對齊 記憶體對齊 記憶體對齊 應該是 編譯器的 管轄範圍 編譯器為程式中的每個 資料單元 對於記憶體對齊問題,主要存在...

什麼是記憶體對齊?為什麼要記憶體對齊?

要了解為什麼要記憶體對齊,首先我們要了解什麼是記憶體對齊 typedef struct a typedef struct b 分別對他們求大小,sizeof a sizeof b 我們所得到的結果是不同的,sizeof a 24而sizeof b 16為什麼會產生不一樣的結果呢?這是非常簡單的乙個例...

C語言 C 為什麼要記憶體對齊

例一 struct aa 例二 struct aa 首先請告訴我,例 一 例二對應的空間大小分別是多少?答案是 12位元組 8位元組。這是為什麼呢?明明有相同的成員,可是為什麼記憶體大小就不一樣呢?這就是接下看來我們要討論的記憶體對其問題了。將每乙個資料的起始位置,在記憶體的對其位置處。無論如何,為...