【C語言】簡單而不嚴謹地理解內存對齊

   

當再次看到自己半年前說的“有時間我會把內存對齊這個補上滴”,內心可是滿滿的懶惰不想動呀[doge]......

下面是正文————————————————

一.爲什麼要內存對齊

       衆所周知,當CPU想從內存中取出數據時,會先將地址通過 地址總線 傳輸給內存,內存通過地址找到對應的數據,而後將數據通過 數據總線 傳送至CPU中去。

       假設地址總線和數據總線都分別有8根(如不加以說明,以下例子全部設定爲地址總線 = 數據總線 = 8),那麼CPU最大所能找到的地址範圍是[0,255](PS:操作系統是32位的,那麼數據總線長度也得是32位的,地址總線至少也得是32位的,所以32位的地址總線最少可以表達的地址數是4294967296種(2的32次方),換成GB(兆字節)就等於4GB。32位的操作系統最大能支持的內存是4GB,因爲超過之後就找不到地址了。)

       當CPU發送一個地址給內存去數據時,我們小腦袋瓜裏面以爲的內存取數據是這樣的:

        有這樣一塊連續的內存,內存拿到地址之後,從左往右逐個逐個取出來放入數據總線中去,假如需要提取八個字節,那麼內存需要取八次數據。而實際上,爲了提高讀取速度,真實的內存是按照這樣子來設計的:

        一條內存條裏面有好多個chip,每個chip裏面又分了好多個bank(俗稱內存顆粒),每個bank裏面有根據行和列將數據按照地址方式進行存儲。而當CPU傳入一個地址時,內存會根據地址找出相應的行和列,在bank裏面進行數據查找,而這個地址對應的並不是一個數據,而是八個數據(一般一個內存顆粒裏面會有八個bank,當然也有更多bank的內存條):

        傳入的地址會在每個bank的同一個位置裏面取出數據,將這八個數據組合在一起成爲我們小腦瓜上以爲的連續的內存,其中取八個數據只需要取一次,比前面說的取八次要快很多。而如果我們有一個2字節的數據,前七個字節都放滿數據了,按照我們小腦袋瓜的理解,這個2字節的數據理論上會放在第八第九位:

       這樣存儲會出現一個問題,因爲這2個字節不在同一塊地址裏面,所以需要取出來的時候會出現取兩次的情況,現取前一塊內存的最後一個字節,再取下一塊內存的第一個字節,將兩個字節拼在一起組成一個數據,這樣取數據會大大地降低內存的讀取速度,爲了提高速度,正確的方法應該是從下一塊內存開始存,前面的內存應該空出來一個地方:

         爲了提高讀取速度,將各種變量按照合適的大小和合適的地址進行存儲的方法就是內存對齊

 

二.怎樣內存對齊

       在知道什麼是內存對齊後,我們來看看怎麼進行內存對齊,內存對齊主要還是要看數據類型的大小以及地址位置。根據編譯器或者操作系統等各種不可抗拒因素,每個數據類型的大小都會有所差異,下面以 char 爲 一字節 ,int 爲 四字節 ,long long爲八字節大小進行說明,以結構體爲例,我們需要遵守的兩個原則:

1.內存相對地址需要是數據類型大小的整數倍

2.存完所有內存後,最後一個數據的內存相對地址要是這堆數據中最類型大小最大的類型的整數倍

例子1:

按照內存對齊原則,應該這樣存儲數據:

char 類型佔一個字節,所以從內存的第一個位置存:

如果沒有內存對齊,那個後面緊跟着的int 類型將會被存在地址爲"1" 的位置去,但是實際上進行了內存對齊後,地址“1”並不是int類型大小"4"的整數倍(1%4 = ?),所以數據不能存在這裏,需要往後面找,一直到地址”4”(4%4 = 0),滿足條件,所以int類型的數據將從這裏開始存:

後面的longlong 類型的數據應該從地址"8"開始存起,計算一下發現當前地址恰好是longlong類型的整數倍(8%8 = 0),可以繼續存,所以又一直往後存八個字節:

而當存完所有數據之後,還沒完,還要看看最後一個地址是多少(例子中爲15),(15%8 =?)顯然不滿足原則的第二點,所以需要往後面空,空到滿足條件爲止,然後發現地址“16”剛好可以(16%8 = 2),所以最後整個結構體大小就確定好了:

例子2,將例子1 換下順序:

char 類型佔一個字節,所以從內存的第一個位置存:

地址“1”並不是int類型大小"8"的整數倍(1%8 = ?),所以數據不能存在這裏,需要往後面找,一直到地址”8”(8%8 = 0),滿足條件,所以longlong類型的數據將從這裏開始存:

後面的int 類型的數據應該從地址"16"開始存起,計算一下發現當前地址恰好是int類型的整數倍(16%4 = 3),可以繼續存,所以又一直往後存四個字節:

而當存完所有數據之後,還沒完,還要看看最後一個地址是多少(例子中爲19),(19%8 =?)顯然不滿足原則的第二點,所以需要往後面空,空到滿足條件爲止,然後發現地址“24”剛好可以(24%8 = 3),所以最後整個結構體大小就確定好了:

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章