記憶體對齊的問題

2021-09-21 04:43:41 字數 1428 閱讀 4013

記憶體對齊問題是每乙個c程式設計師都應該考慮過的問題,c編譯器的規則明確規定了對齊問題,就是乙個struct中按照最長的型別對齊,比如考慮下面的結構體:

struct abc

在32位x86機器上它的大小是多少呢?是12,為什麼呢?因為該結構體中最長的型別是int,因此需要按照4位元組對齊,因此a和c後面都要pad進去3個無辜的位元組,是不是太浪費了呢?是的,但是如果該結構體不是非這樣設計不可(如果是網路協議之類的既定協議就不能隨意更換,這涉及協議設計問題,不深談),你完全可以將b和c對換一下位置,這樣的話,大小將會成為8,能否再節省一些呢?可以,那就是用pack偽指令取消編譯器的記憶體對齊,但是代價是效率更低以及更不安全,首先看一下為何效率更低。

32位cpu上,資料匯流排是32位的,一次訪問32位的資料,如果不對齊,那麼考慮cpu訪問完a然後訪問b的情況,訪問完a,一次訪問了a開始的32位4位元組的資料,此時僅有開始的8個位元組是有效的(以下不考慮大小端),後面的3個位元組被丟棄,然後訪問b,繼續向前推進制址匯流排,就是位址為a的位址加4,那麼得到的是4位元組b的最後乙個位元組和c然後跟著乙個無關的兩個位元組的結構外的資料,為了得到b的前三個位元組,位址必須退回到a的位址,然後拋棄a從而得到後面的三個位元組,或者直接退回到a的位址的下乙個位址,但是這種情況下直接就可以得到b,前面得到的b的最後乙個位元組就沒有用了,不管怎樣最少需要三次訪存,即使cpu可以精確到正好將位址回退到b的位址,回退匯流排也沒有順序推進匯流排高效。如果是4位元組對齊的,那麼在訪問完a後,直接訪問下乙個4位元組就可以了,這就體現了高效性。

很多人都認為寫比讀更麻煩,對於cpu而言是這樣嗎?cpu要想讀乙個資料,第一步必須將位址匯流排設定好,然後在下乙個週期才能在資料匯流排得到資料,然而對於寫操作,cpu可以一步完成,直接將位址放到位址匯流排,並且將資料置於資料匯流排就可以了,乙個週期就可以完成,因此對於cpu而言,寫比讀更容易。以上是乙個無關緊要的話題,現在考慮多cpu的情況,多個cpu連線的是同乙個位址匯流排以及同乙個資料匯流排,也就是說記憶體是單進單出的,至於怎麼路由到多個cpu並不是儲存器本身的問題,一般而言乙個匯流排週期只能由乙個cpu控制匯流排,如果資料沒有對齊,那麼由於需要額外的很多次匯流排操作,那麼就會出現一種情況,即乙個cpu操作完了匯流排讀到了4個位元組中的1個位元組,還剩下3個位元組沒有讀,此時其它cpu控制了匯流排,在剩下的3個位元組的位址處寫入了資料,那麼等到第乙個cpu再次控制匯流排時就會得到錯誤的資料,雖然這件事事實上不會發生,但是必然擁有制止這件事發生的措施,既然有了措施就一定有了開銷,如果資料是對齊的,那麼這種開銷就不會有,簡單的說也是提高了效率。

因此很多32位的cpu直接禁掉了位址匯流排的低兩位,所以該類cpu只能訪問4位元組對齊的資料,另一些cpu會捕獲訪問不對齊的資料,這裡有乙個很古老的話題,就是為何乙個位元組是8位,因為老的成型的cpu的匯流排寬度是8位!實際上當今的cpu中這類對齊優化已經沒有純粹的優化意義了,因為區域性原理連同cpu的cache會掩蓋對齊得到的優化。cpu的優化原則是對於長度為n的資料的位址被分配到n的整數倍,這樣就會在訪問完該資料後順序的到達下乙個資料而不需要切割操作。

記憶體對齊的問題

記憶體對齊問題是每乙個c程式設計師都應該考慮過的問題,c編譯器的規則明確規定了對齊問題,就是乙個struct中按照最長的型別對齊,比如考慮下面的結構體 struct abc char a int b char c 在32位x86機器上它的大小是多少呢?是12,為什麼呢?因為該結構體中最長的型別是in...

記憶體對齊問題

一直困惑自己有兩個問題 1.程式為什麼要做記憶體對齊?1.處理器訪問記憶體是粒度為多位元組時,如果資料不是在邊界處,則,處理器需要分多個時鐘週期進行資料的訪問。2.增加可移植性。並非所有的處理器都可以訪問任何位址,可能出現硬體錯誤。具體可以參考 2.struct中如何計算記憶體對齊?先說說c語言中s...

記憶體對齊問題

首先由乙個程式引入話題 1 環境 vc6 windows sp22 程式13 include iostream 45 using namespace std 67 struct st1 8 1314 struct st215 20 21int main 2227 程式的輸出結果為 sizeof st...