(廢話:最近接觸到記憶體對齊概念,針對記憶體對齊的規則,我在vc中一一進行了驗證,發現編譯器確實對我的資料進行了記憶體對齊。我便知道記憶體對齊必定是有它的優點所在,是什麼呢?我找的資料都是說記憶體對齊可以提高記憶體訪問效率、可移植到不同的平台等等,但是為什麼會這樣呢,沒有一個清晰的解釋。下面便是我多天努力的成果!)
編譯器為什麼要替我們記憶體對齊?學了電腦群組成原理,瞭解了記憶體的基本單元是一個位元組,記憶體可以隨機定址,於是乎我天真的認為記憶體就是一個位元組型的容器,基本單位是單個位元組。
Figure 1. 我眼中的記憶體空間布局悲劇的是,記憶體讀寫的真正訪問者cpu不是這麼想的。cpu是根據記憶體訪問粒度(memory access granularity,下文簡寫成MAG)來讀取記憶體,MAG就是cpu一次記憶體訪問操作的資料量,具體數值依賴於特定的平台,一般是2byte、4byte、8byte。
Figure 2. cpu眼中的記憶體空間布局因此,程式員和cpu看待記憶體空間布局是存在差異的。唉,既不能過多的苛刻程式員,又要讓cpu舒服,怎麼辦呢?只好讓編譯器來對我們的代碼進行隱式的記憶體對齊(當然它能做的只是幫程式中的資料進行記憶體對齊,至於直接用指標去訪問記憶體,它是不會管的)。
向開發編譯器的大大們致敬!記憶體對齊的好處下面用一個小執行個體來剖析記憶體對齊的好處:很簡單,在32位的機器下,分別訪問一個記憶體對齊的地址空間(從地址0開始)和一個沒有對齊的地址空間(從地址1開始),讀取四個位元組到cpu的寄存器中,比較兩者的讀取過程。
Case1:記憶體訪問粒度為1個位元組(cpu眼中的記憶體模型等價於程式員眼中的記憶體模型):
Figure 3. MAG=1Result:讀取4個位元組,兩者都需要進行4次記憶體訪問操作。打平,在MAG=1的情況下不需要考慮記憶體對齊。
Case2:記憶體訪問粒度為2個位元組:
Figure 4. MAG=2Result:讀取4個位元組,左邊的(記憶體對齊地址)只需要進行2次記憶體訪問操作,右邊的需要進行3次記憶體訪問操作+附加操作(見下文)。記憶體對齊地址取勝!
Case3:記憶體訪問粒度為4個位元組:
Figure 5. MAG=4
Result:讀取4個位元組,左邊的只需要進行1次記憶體訪問操作,右邊的需要進行2次記憶體訪問操作+附加操作。記憶體對齊地址再次取勝!
Conclusion:記憶體對齊地址vs沒有記憶體對齊的地址,在三種不同的記憶體訪問粒度下,取得了2勝一平的完勝戰績。對於32位的機器,實際的記憶體訪問粒度是4個位元組,原因如下:
- 每一次記憶體訪問操作需要一個常量開銷;
- 在資料量一定的情況下,減少記憶體訪問操作,能提高程式運行效能;
- 增大記憶體訪問粒度(當然不超過資料匯流排的頻寬),能減少記憶體訪問操作(從上面的執行個體就能夠看出來);
一句話,記憶體對齊確實可以提高程式效能。cpu如何處理沒有記憶體對齊的資料訪問?繼續分析上面那個執行個體,在記憶體訪問粒度為2、從地址1開始讀取四個位元組的cpu處理過程(硬體方式):
- 讀取資料所在的第一塊記憶體空間(0-1),移除多餘位元組(0);
- 讀取資料所在的第二塊記憶體空間(2-3);
- 讀取資料所在的第三塊記憶體空間(4-5),移除多餘位元組(5);
- 把三塊資料拼接起來(1-4),放入寄存器中。
訪問一塊相同大小的資料,記憶體對齊的優勢是多麼的巨大!如果cpu能這麼來處理,也只不過是影響了我們程式的運行效能,至少還是能啟動並執行!悲劇的是,以前的cpu並沒有這麼“勤快”,遇到沒有記憶體對齊的資料訪問,它會直接拋出一個異常:作業系統可能會響應這個異常,用軟體的方式來處理,效能只會更差;或者程式直接崩潰掉。
一句話,記憶體對齊的代碼確實具有更高的可移植性!Over!更多內容,參照此文:https://www.ibm.com/developerworks/library/pa-dalign/記憶體對齊的具體規則,參照此篇部落格:http://blog.csdn.net/liu1064782986/article/details/7600979