1. 程式人生 > >什麼是記憶體?以及記憶體的編址方法和記憶體對齊

什麼是記憶體?以及記憶體的編址方法和記憶體對齊

 什麼是記憶體? (硬體和邏輯兩個角度)
從硬體角度:記憶體實際上是電腦的一個配件(一般叫記憶體條)。根據不同的硬體實現原理還可以把記憶體分成SRAM和DRAM (DRAM又有好多代,譬如最早的SDRAM,後來的DDR1、DDR2 ... .. LPDDR)
從邏輯角度:記憶體是這樣一種東西,它可以隨機訪問(隨機訪問的意思是隻要給一一個地址,就可以訪問這個記憶體地址)、並且可以讀寫(當然了邏輯上也可以限制其為只讀或者只寫) ;記憶體在程式設計中天然是用來存放變數的(就是因為有了記憶體,所以c語言才能定義變數,c語言中的一個變數實際就對應記憶體中的一個單元)

記憶體的邏輯抽象圖(記憶體的程式設計模型)

從邏輯角度來進,記憶體實際上是由無限多個記憶體單元格組成的,每個單元格有一個固定的地址叫記憶體地址,這個內在地址和這個記憶體單元格唯一對應且永久繫結。

以大樓來類比記憶體是最合適的。邏輯上的記憶體就好象是一棟無限大的大樓,記憶體的單元格就好象太樓蟲的一個個小房間。每個記憶體單元格的地址就好象每個小房間的房間號。記憶體中儲存的內容就好象住在房間蟲的人一樣。

邏輯上來說,記憶體可以有無限大(因為數學上編號永遠可以增加,無盡頭)。但是現實中實際的記憶體大小是有限制的,譬如32位的系統(32位系統指的是32位資料線,但是一般地址線也是32位,這個地址線32位決定了記憶體地址只能有32位二進位制,所以邏輯上的大小為2的32次方)記憶體限制就為4G(譬如我32位CPU裝32位windows,但實際電腦只有512M記憶體)。  

記憶體位寬(硬體和邏輯兩個角度)

從硬體角度講:硬體記憶體的實現本身是有寬度的,也就是說有些記憶體條就是8位的,而有些就是16位的。那麼需要強調的是記憶體晶片之間是可以並聯的,通過並聯後即使8位的記憶體晶片也可以做出來16位或32位的硬體記憶體。

從邏輯角度講:記憶體位寬在邏輯上是任意的,甚至邏輯上存在記憶體位寬是24位的記憶體(但是實際上這種硬體是買不到的,也沒有實際意義)。從邏輯角度來講不管記憶體位寬是多少,我就直接操作即可,對我的操作不構成影響。但是因為你的操作不是純邏輯而是需要硬體去執行的,所以不能為所欲為,所以我們實際的很多操作都是受限於硬體的特性的。譬如24位的記憶體邏輯上和32位的記憶體沒有任何區別,但實際硬體都是32位的,都要按照32位硬體的特性和限制來幹活。

 

位和位元組
記憶體單元的大小單位有4個:位(1bit)   位元組(8bit)   半字(一般是16bit)       字 (一般是32bit)
在所有的計算機、所有的機器中(不管是32位系統還是16位系統還是以後的64位系統),位永遠都是1bit,位元組永遠都是8bit。

字和半字

歷史上曾經出現過16位系統、32位系統、64位系統三種,而且作業系統還有windows、linux、 ios等很多,所以很多的概念在歷史上曾經被混亂的定義過。

建議大家對字、半字、雙字這些概念不要詳細區分,只要知道這些單位具體有多少位是依賴於平臺的。實際工作中在每種平臺上先去搞清楚這個平臺的定義(字是多少位,半字永遠是字的一-半,雙字永遠是字的2倍大小),程式設計時一般根本用不到字這個概念,那我們區分這個概念主要是因為有些文件中會用到這些概念,如果不加區別可能會造成你對程式的誤解。在linux+ARM這個軟硬體平臺上,字是32位的。

 

記憶體編址方法

記憶體在邏輯上就是一個一個的格子,這些格子可以用來裝東西(裡面裝的東西就是記憶體中儲存的數),每個格子有一個編號,這個編號就是記憶體地址,這個記憶體地址(一個數字)和這個格子的空間(實質是一個空間)是一一對應且永久繫結的。這就是記憶體的編址方法。

在程式執行時,計算機中CPU實際只認識記憶體地址,而不關心這個地址所代表的空間在哪裡,怎麼分佈這些實體問題。因為硬體設計保證了按照這個地址就一定能找到這個格子,所以說記憶體單元的2個概念:地址和空間是記憶體是記憶體單元的兩個方面。

     關鍵:記憶體編址是以位元組為單位的

我隨便給一個數字(譬如說7),然後說這個數字是一個記憶體地址,然後問你這個記憶體地址對應的空間多大?這個大小是固定式,就是一個位元組(8bit)。
如果把記憶體比喻位一棟大樓,那麼這個樓裡面的一個一個房間就是一個一個記憶體格子,這個格子的大小是固定的8bit,就好象這個大樓裡面所有的房間戶型是一樣的。



記憶體和資料型別的關係

C語言中的基本資料型別有: char short int long float double

整形(整數型別,這個整就體現在它和CPU本身的資料位寬是一樣的)譬如32位的CPU,整形就是32位,int :就是32位。

資料型別和內在的關係就在於,資料型別是用來定義變數的,而這些變數需要儲存、運算在記憶體中所以資料型別必須和記憶體相匹配才能獲得最好的效能,否則可能不工作或者效率低下。

在32位系統中定義變數最好用int,因為這樣效率高。原因就在於32位的系統本身配合記憶體等也是32位,這樣的硬體配置天生適合定義32位的int型別變數,效率最高。也能定義8位的char型別變數或者16位的short型別變數,但是實際上訪問效率不高。

在很多32位環境下,我們實際定義bool型別變數(實際只需要1個bit就夠了)都是用int來實現bool的。也就是說我們定義一個bool b1;時,編譯器實際幫我們分配了32位的記憶體來儲存這個bool變數b1。編譯器這麼做實際上浪費了31位的記憶體,但是好處是效率高。

問題:實際程式設計時要以省記憶體為大還是要以執行效率為重?答案是不定的,看縣體情況。很多年前記憶體很貴機器上記憶體都很少,那時候寫程式碼以省記憶體為主。現在隨著半導體技術的發展記憶體變得很便宜了,現在的機器都是高配,不在乎省一點記憶體,而效率和使用者體驗變成了關鍵。所以現在寫程式大部分都是以效率為重。

 

記憶體對齊

我們在c中int a;定義一-個int型別變數,在記憶體中就必須分配4個位元組來儲存這個a。有這麼2種不同記憶體分配思路和策略:

(如圖)第一種:0  1  2  3                          對齊訪問

            第二種:1  2  3  4 或者 2  3  4  5 或者 3  4  5  6   非對齊訪問

 

記憶體的對齊訪問不是邏輯的問題,是硬體的問題。從硬體角度來說,32位的記憶體它0123四個單元本身邏輯上就有相關性,這4個位元組組合起來當作一個int硬體上就是合適的,效率就高。

對齊訪問很配合硬體,所以效率很高,非對齊訪間因為和硬體本身不搭配,所以效率不高。... S因為相容性的問題,一般硬體也都提供非對齊訪間,但是效率要低很多。