[TOC]
# 內存的概念
## 內存
程序和數據平常存儲在硬盤(硬盤是一種可記憶盤)等存儲器上,不管你開機或關機了,它們都是存在的,不會丟失。
硬盤可以存儲的東西很多,但其傳輸數據的速度較慢。所以需要運行程序或打開數據時,這些數據必須從硬盤等存儲器上先傳到**另一種容量小但速度快得多的存儲器**(無記憶盤),之后才送入CPU進行執行處理。
這中間的存儲器就是內存。
**每個數據,都需要在內存上有其映射地址**。內存是如何進行編址,那屬于操作系統。
## 計算機內存
開啟電源,啟動BIOS,CPU工作,調用內存,內存跟硬盤索要資源
當你點擊一個文件的時候數據經過數據總線傳達到CPU,CPU發送指令到內存,內存那里會跟硬盤溝通,問他有沒有這個東西,他說有,你就會看到這個文件夾里面是什么東西。
RAM 是隨機存取存儲器,它的特點是易揮發性,掉電即失。`媽蛋,難怪一斷電,我的東西沒保存,就找不到了`
既然內存是用來存放當前正在使用的(即執行中)的數據和程序,那么它是怎么工作的呢?我們平常所提到的計算機的內存指的是動態內存(即[DRAM](http://baike.baidu.com/view/3312702.htm)),動態內存中所謂的“動態”,指的是當我們將數據寫入DRAM后,經過一段時間,數據會丟失,因此需要一個額外設電路進行[內存刷新](http://baike.baidu.com/view/329588.htm)操作。
具體的工作過程是這樣的:一個DRAM的[存儲單元](http://baike.baidu.com/view/1223079.htm)存儲的是0還是1取決于電容是否有[電荷](http://baike.baidu.com/view/63129.htm),有電荷代表1,無電荷代表0。但時間一長,代表1的電容會放電,代表0的電容會吸收電荷,這就是數據丟失的原因。刷新操作定期對電容進行檢查,若電量大于滿電量的1/2,則認為其代表1,并把電容充滿電;若電量小于1/2,則認為其代表0,并把電容放電,藉此來保持數據的連續性。
* * * * *
* ROM(只讀存儲器或者固化存儲器)
* RAM(隨機存取存儲器)
ROM和RAM指的都是半導體存儲器,ROM是Read Only Memory的縮寫,RAM是Random Access Memory的縮寫。ROM在系統停止供電的時候仍然可以保持數據,而RAM通常都是在掉電之后就丟失數據,典型的RAM就是計算機的內存。
### 為什么計算機內存,硬盤能存儲數據
硬件技術是不斷發展的,所以,只能說下基本原理:磁碟的表面有很多微小的小顆粒,能夠被磁化。利用消磁和磁化原理來標識數據。
1字節,有8位二進制,一個字節能表示 255 個值(0000 0000 ~ 1111 1111 )
**程序要執行,首先將文件加載到內存中。
內存的每一個區域是有內存地址的,一個內存單元為一個字節。
程序加載到內存中,就會占用一部分區域,這一部分區域就是使用內存單元的范圍來標識的。**
### 內存的存儲原理
內存,英文名為RAM(Random Access Memory),全稱是隨機存取存儲器。主要的作用就是存儲代碼和數據供CPU在需要的時候調用。但是這些數據并不是像用木桶盛水那么簡單,而是類似圖書館中用有格子的書架存放書籍一樣,不但要放進去還要能夠在需要的時候準確的調用出來,雖然都是書但是每本書是不同的。對于內存等存儲器來說也是一樣的,雖然存儲的都是代表0和1的代碼,但是不同的組合就是不同的數據。讓我們重新回到書和書架上來。
如果有一個書架上有10行和10列格子(每行和每列都有0~9編號),有100本書要存放在里面,那么我們使用一個行的編號和一個列的編號就能確定某一本書的位置。如果已知這本書的編號36,那么我們首先鎖定第3行,然后找到第6列就能準確的找到這本書了。
在內存中也是利用了相似的原理現在讓我們回到內存上,對于它而言數據總線是用來傳入數據或者傳出數據的。因為存儲器中的存儲空間是如果前面提到的存放圖書的書架一樣通過一定的規則定義的,所以我們可以通過這個規則來把數據存放到存儲器上相應的位置,而進行這種定位的工作就要依靠**地址總線**來實現了。
對于CPU來說,內存就像是一條長長的有很多空格的“線”,每個空格都有一個唯一的地址與之相對應。如果CPU想要從內存中調用數據,它首先需要給地址總線發送地址數據定位要存取的數據,然后等待若干個時鐘周期之后,數據總線就會把數據傳輸給CPU。當地址解碼器接收到地址總線送來的地址數據之后,它會根據這個數據定位CPU想要調用的數據所在的位置,然后數據總線就會把其中的數據傳送到CPU。
CPU在一行數據中每次只是存取1個字節的數據。回到實際中,通常CPU每次需要調用64bit或者是128bit的數據(單通道內存控制器為64bit,雙通道為128bit)。
如果數據總線是64bit的話,CPU就會在一個時間中存取8個字節的數據,因為每次還是存取1個字節的數據,64bit總線將不會顯示出來任何的優勢,工作的效率將會降低很多。
這也就是現在的主板和CPU都使用雙通道內存控制器的原因。
## 地址總線、數據總線,控制總線。
### 基本理解
在計算機內部每個有效信息,必須具有**3個基本屬性:內容,指向,行為**
這三個屬性要通過先個總線實現:數據總線,地址總線,控制總線。
好比:一封信件的內容、地址和信件狀態,比如一封信到你家門口,郵遞員大喊一聲:“二狗子,你的信來了!”。
在計算機內部數據在**數據總線**上傳遞,每條傳輸線我們稱之為1位,各個傳輸線按序排列他們之間是并行關系。
**地址總線**也是一樣的,數據總線決定每次傳輸數據的大小,地址總線決定cpu所能訪問最大內存空間大小。
**控制總線**反映了數據的狀態和傳輸方式,它是地址總線的擴展補充。
### 比喻
用經十路和經十路路邊的單位數來對數據總線和地址總線寬度進行介紹:
2003年,濟南市開始經十路的拓寬,由原來的雙向4車道,拓寬為雙向8車道
從通行能力上看,8車道顯然比4車道通行能力強——也就是,一次通行的車輛比4車道多。因此經十路車道的寬度,就好比計算機中數據總線的寬度,數據總線越寬,計算機一次處理的數據就越多!
經十路沿線有很多單位,需要對沿街單位進行編號,如山東大學千佛山校區為經十路73號。在2000年時,沿街單位不過1000家,因此用0~999就可以對所有單位編號,但經十路拓寬后,帶動了沿街經濟的發展,后來有蓋了很多樓,增加了很多單位,假設現在增加到1萬家,那么單位編號就需要0~9999才能實現對所有單位的編號。
從上面看,對1000家單位,只需要號牌能裝三位數字即可,假定單位號牌規定了每個數字的大小,則三位的號牌就只能編址到999,最多1000家單位。而對于1萬家單位,則需要4位的號牌!
這里號牌所能裝的數字的多少,就好比地址總線的寬度——地址總線越寬,它能編址訪問的內存空間就越大,這里內存空間就好比沿街單位,若內存空間超過了編址的范圍,就像1萬家單位超過了3位號牌的編址范圍,則多出去的空間,就沒法編址進行訪問了!
## 內存中的數據
數據在內存中始終是以二進制形式存放的。
1. 數值是以補碼表示的。
2. 整型:
一個正數的補碼和其原碼的形式相同。而負數的補碼方式是將其絕對值的二進制形式“按位求反再加1”
3. 實型:
在內存中占4個字節,是按照指數形式存儲的,實型數據分為小數部分和指數部分,分別存放!計算機用二進制表示小數部分,用2的冪次來表示指數部分!
4. 字符型:
在內存中字符的存儲實際上是把字符相對應的ASCII代碼放到存儲單元中的。而這些ASCII代碼值在計算機中也是以二進制形式存放的。這個與整型的存儲很相似。因此這兩類之間的轉換也比較方便!
5. 字符數據
系統在表示一個字符型數據時,并不是將字符本身的形狀存入內存,而只是將字符的ASCII碼存入內存。在內存中所有的數據又是以二進制的形式存放的。例子中'c1'、'c2'在內存中的表示如下:

'c1'、'c2'的ASCII碼為97、98。而97、98的二進制形式為`01100001`、`01100010`。
所以'c1'、'c2'在內存中的表示為 `01100001`、`01100010`。
## 內存地址
內存地址空間是用16進制的數據表示, 如`0x8049324`, 那為什么需要用十六進制表示呢? 十六進制的意義何在?
編程中,我們常用的還是10進制.畢竟C/C++是高級語言。
比如:`int a = 100,b = 99`;
不過,由于數據在計算機中的表示,最終以二進制的形式存在,所以有時候使用二進制,可以更直觀地解決 問題。但二進制數太長了。比如int 類型占用4個字節,32位。比如100,用int類型的二進制數表達將是:
~~~
0000 0000 0000 0000 0110 0100
~~~
面對這么長的數進行思考或操作,沒有人會喜歡。因此,C,C++ 沒有提供在代碼直接寫二進制數的方法。用16進制或8進制可以解決這個問題。因為,進制越大,數的表達長度也就越短。
**不過,為什么偏偏是16或8進制,而不其它的,諸如9或20進制呢?**
2、8、16,分別是2的1次方,3次方,4次方。這一點使得三種進制之間可以非常直接地互相轉換。8進制或16進制縮短了二進制數,但保持了二進制數的表達特點。
### 十六進制表示
十六進制的意義:
1. 用于計算機領域的一種重要的數制
2. 對計算機理論的描述,計算機硬件電路的設計都是很有益的。比如邏輯電路設計中,既要考慮功能的完備,還要考慮用盡可能少的硬件,十六進制就能起到一些理論分析的作用。比如四位二進制電路,最多就是十六種狀態,也就是一種十六進制形式,只有這十六種狀態都被用上了或者盡可能多的被用上,硬件資源才發揮了盡可能大的作用。
3. 十六進制更簡短,因為換算的時候一位16進制數可以頂4位2進制數。
十六進制的表示:
C語言、Shell、Python語言及其他相近的語言使用字首`0x`,例如`0x5A3`。開頭的`0`令解析器更易辨認數,而“x”則代表十六進制(就如`O`代表八進制)。在`0x`中的`x`可以大寫或小寫。
### 十六進制內存地址
一個內存地址存著一個對應的值, 內存就相當于`(addr,val)`的大hash表,c語句的語義基本就是改變hash值。
如 `int i = 3`;
假設 `i` 的內存地址為 `0x8049320` ,那么這句話的語義是`0x8049320 = 3`,經過`i = 3`后,`i`為`(0x8049320,3)`
如 `int b = i`;
假設 b的內存地址為 `0x8049324` ,那么這句話的語義是`0x8049324 = i`對應的`val = 3`,此時`b`為`(0x8049324,3)`