GNU C - 关于8086的内存访问机制以及内存对齐(memory alignment)
接著前面的文章,這篇文章就來說說menory alignment -- 內(nèi)存對齊.
?
一、為什么需要內(nèi)存對齊?
?
無論做什么事情,我都習慣性的問自己:為什么我要去做這件事情? 是啊,這可能也是個大家都會去想的問題,
因為我們都不能稀里糊涂的或者。那為什么需要內(nèi)存對齊呢?這要從cpu的內(nèi)存訪問機制說起.
?
為了了解清楚cpu的內(nèi)存訪問機制,昨天整晚都在查找資料,但是還是找不到很好的介紹資料.后來只是找到了相關
的一些介紹的博客。 這些博客中大多都是以介紹內(nèi)存對齊為主要目的,然后順帶著說一下cpu的內(nèi)存訪問機制,所以
找不到權威的資料,后來聽說<<匯編語言編程藝術>>這本書里面有關于x86的系統(tǒng)介紹,就下載了一份PDF,但是
也還是沒有找到.
?
所以呢下面的一些關于x86的內(nèi)存訪問方面的只是很多都是來源于一些比較好的博客.在文章的最后我會注明參考的
博客鏈接,作為擴展閱讀.
?
簡單介紹x86的內(nèi)存訪問機制:
1.內(nèi)存的寫入操作: cpu把需要寫入的地址放入地址總線, 把需要寫入的數(shù)據(jù)放入數(shù)據(jù)總線, 把控制總線置為寫入操作.
???????? 然后內(nèi)存子系統(tǒng)根據(jù)地址總線選定內(nèi)存單元, 檢查控制總線發(fā)現(xiàn)是寫入操作,則入去數(shù)據(jù)總線數(shù)據(jù), 寫入相關內(nèi)存
???????? 單元.
?
2.內(nèi)存的讀入操作: cpu把需要讀入的地址放入地址總線, 把控制總線置為讀入操作. 內(nèi)存子系統(tǒng)根據(jù)地址總線選定內(nèi)存
???????? 單元, 檢查控制總線發(fā)現(xiàn)是讀入操作, 則讀取內(nèi)存單元中的數(shù)據(jù), 寫入數(shù)據(jù)總線.
?
?16bit數(shù)據(jù)總線: 每個內(nèi)存周期,cpu只能讀取一個偶單元和一個奇單元,地址總線的地址是偶單元的地址,所以地址總線的地址永遠是2對齊的.
??????? 每個內(nèi)存周期,可以讀取一個字,也就是16bit.
?? 1.讀取一個字,如果是以2對齊的,則只需要一個內(nèi)存周期即可完成.如果數(shù)據(jù)不是以2對齊的,則需要2個內(nèi)存周期.
?? 2.讀取雙字: 如果是以2對齊的,則只需要2個內(nèi)存周期即可完成,如果數(shù)據(jù)不是以2對齊的,則需要3個內(nèi)存周期完成.
?
32bit數(shù)據(jù)總線: 每個內(nèi)存周期,讀取的數(shù)據(jù)地址都是以4對齊的.一個內(nèi)存周期可以讀取一個雙字,也就是32bit.
??? 1.如果讀取一個雙字,地址是以4對齊的話,則只需要一個內(nèi)存周期即可完成.如果不是以4對齊,則需要2個內(nèi)存周期完成.
??? 2.如果讀取一個字,地址是對4取模余3的話,那么需要2個內(nèi)存周期完成對數(shù)據(jù)的讀取.地址如果對4去模不余3的話,則
?????? 只需要一個內(nèi)存周期即可完成數(shù)據(jù)讀取.
??? 3. 對于字節(jié), 任何字節(jié)地址讀取只需要一個內(nèi)存周期.
?
通過上面可以看得出,為什么16bit數(shù)據(jù)總線cpu是以2對齊的,而32bit數(shù)據(jù)總線cpu是以4對齊的. 最主要的原因是能夠在最小的
內(nèi)存周期內(nèi)完成對地址的訪問,提高cpu的效率.
?
二、內(nèi)存對齊的作用
?? 如果不采用內(nèi)存對齊機制的話,有些地址的訪問需要在多個內(nèi)存周期內(nèi)完成,而且還需要多次內(nèi)存周期讀取的高低字節(jié)
進行拼湊,然后得到32bit數(shù)據(jù).? 如果使用內(nèi)存對齊機制,不僅可以減少對地址訪問過程中需要的內(nèi)存周期,而且還避免了
高低字節(jié)的數(shù)據(jù)拼湊,提高了cpu的工作效率.
?
三、編譯器是如何處理內(nèi)存對齊的?
?
struct mem_alignment {char a;int b;char c; };?
?
?在32位x86機器上面它的大小是12. 另外一個問題,如果結(jié)構體中的成員變量順序不一樣會導致該結(jié)構在內(nèi)存中的長度
?也不一樣,就像上面,如果改成下面這個樣子:
?
struct mem_alignment {char a;char c;int b; };?
?那么它的大小就變成了8.
?
?如果我們使用緊湊的對齊方式 __attribute__((packed)) or? __attribute__((aligned (1)))的話,
?那么struct mem_alignment的大小應該是6.?或者是使用偽指令#pragma pack (1).
?
#pragma pack (1)struct mem_alignment {char a;char c;int b; };#pragma pack ()?
?
? 上面最后一句的作用是恢復編譯器默認的對齊方式.
?
關于內(nèi)存對齊方面的知識就總結(jié)到這里. 也算是對前面文章的交代了~
?
參考資料:
????????? <<從80X86結(jié)構看內(nèi)存對齊問題>>?http://my.unix-center.net/~Simon_fu/?p=262
????????? <<oschina 內(nèi)存對齊的問題>>? http://www.oschina.net/question/234345_48055
????????? <<Thinking in linux C/C++字節(jié)對齊詳解>> http://www.linuxsong.org/2010/09/c-byte-alignment/
?
轉(zhuǎn)載于:https://www.cnblogs.com/respawn/archive/2012/07/10/2585334.html
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的GNU C - 关于8086的内存访问机制以及内存对齐(memory alignment)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 图解SQL的inner join、lef
- 下一篇: 简明Python3教程 16.标准库