what's the 內存
內存(Memory)是計算機中最重要的部件之一,它是程序與 CPU 進行溝通的橋梁。計算機中所有程序的運行都是在內存中進行的,因此內存對計算機的影響非常大,內存又被稱為主存,其作用是存放 CPU 中的運算數據,以及與硬盤等外部存儲設備交換的數據。只要計算機在運行中,CPU 就會把需要運算的數據調到主存中進行運算,當運算完成后 CPU 再將結果傳送出來,主存的運行也決定了計算機的穩定運行。
內存的物理結構
內存的內部是由各種 IC 電路組成的,它的種類很龐大,但是其主要分為三種存儲器
- 隨機存儲器(RAM):內存中最重要的一種,表示既可以從中讀取數據,也可以寫入數據。當機器關閉時,內存中的信息會丟失。
- 只讀存儲器(ROM):ROM 一般只能用於數據的讀取,不能寫入數據,但是當機器停電時,這些數據不會丟失。
- 高速緩存(Cache):Cache 也是我們經常見到的,它分為一級緩存(L1 Cache)、二級緩存(L2 Cache)、三級緩存(L3 Cache)這些數據,它位於內存和 CPU 之間,是一個讀寫速度比內存更快的存儲器。當 CPU 向內存寫入數據時,這些數據也會被寫入高速緩存中。當 CPU 需要讀取數據時,會直接從高速緩存中直接讀取,當然,如需要的數據在Cache中沒有,CPU會再去讀取內存中的數據。
內存 IC 是一個完整的結構,它內部也有電源、地址信號、數據信號、控制信號和用於尋址的 IC 引腳來進行數據的讀寫。下面是一個虛擬的 IC 引腳示意圖

圖中 VCC 和 GND 表示電源,A0 - A9 是地址信號的引腳,D0 - D7 表示的是控制信號、RD 和 WR 都是好控制信號,我用不同的顏色進行了區分,將電源連接到 VCC 和 GND 后,就可以對其他引腳傳遞 0 和 1 的信號,大多數情況下,+5V 表示1,0V 表示 0。
D0 - D7 表示的是數據信號,也就是說,一次可以輸入輸出 8 bit = 1 byte 的數據。A0 - A9 是地址信號共十個,表示可以指定 00000 00000 - 11111 11111 共 2 的 10次方 = 1024個地址。每個地址都會存放 1 byte 的數據,因此我們可以得出內存 IC 的容量就是 1 KB。
內存的讀寫過程
來看一個對內存 IC 進行數據寫入和讀取的模型

來詳細描述一下這個過程,假設要向內存 IC 中寫入 1byte 的數據,過程是這樣的:
- 首先給 VCC 接通 +5V 的電源,給 GND 接通 0V 的電源,使用 A0-A9 來指定數據的存儲場所,然后再把數據的值輸入給 D0-D7 的數據信號,並把 WR(write)的值置為 1,執行完這些操作后,即可以向內存 IC 寫入數據
- 讀出數據時,只需要通過 A0 - A9 的地址信號指定數據的存儲場所,然后再將 RD 的值置為 1 即可。
- 圖中的 RD 和 WR 又被稱為控制信號。其中當WR 和 RD 都為 0 時,無法進行寫入和讀取操作。
內存的現實模型
為了便於記憶,這里把內存模型映射成為現實世界的模型,在現實世界中,內存的模型很像樓房。在這個樓房中,1層可以存儲一個字節的數據,樓層號就是地址,下面是內存和樓層整合的模型圖

程序中的數據不僅只有數值,還有數據類型的概念,從內存上來看,就是占用內存大小(占用樓層數)的意思。即使物理上強制以 1 個字節為單位來逐一讀寫數據的內存,在程序中,通過指定其數據類型,也能實現以特定字節數為單位來進行讀寫。
what's the 二進制
計算機的底層都是使用二進制數據進行數據流傳輸的,那么為什么會使用二進制表示計算機呢?或者說,什么是二進制數呢?在拓展一步,如何使用二進制進行加減乘除?
首先、什么是二進制數呢?為了說明這個問題,可以把 00100111 這個數轉換為十進制數看一下,二進制數轉換為十進制數,直接將各位置上的值 * 位權即可

二進制數代表的 00100111 轉換成十進制就是 39,這個 39 並不是 3 和 9 兩個數字連着寫,而是 3 * 10 + 9 * 1,這里面的 10 , 1 就是位權,以此類推,上述例子中的位權從高位到低位依次就是 7 6 5 4 3 2 1 0。這個位權也叫做次冪,那么最高位就是 2 的 7 次冪,2 的 6 次冪 等等。二進制數的運算每次都會以 2 為底,這個 2 指得就是基數,那么十進制數的基數也就是 10 。在任何情況下位權的值都是 數的位數 - 1,那么第一位的位權就是 1 - 1 = 0, 第二位的位權就睡 2 - 1 = 1,以此類推。
二進制數其實就是 用0和1兩個數字來表示的數,它的基數為2,它的數值就是每個數的位數 * 位權再求和得到的結果,我們一般說的數值都是指十進制數,那么它的數值就是 3 * 10 + 9 * 1 = 39。
移位運算
接下來看一下二進制的運算,和十進制數一樣,加減乘除也適用於二進制數,只要注意逢 2 進位即可。
首先來看一下移位運算,移位運算是指將二進制的數值的各個位置上的元素坐左移和右移操作,見下圖

補數
接下來看一下右移的情況,右移之后空出來的高位數值,有 0 和 1 兩種形式。要想區分什么時候補 0 什么時候補 1,首先需要掌握二進制數表示負數的方法。
二進制數中表示負數值時,一般會把最高位作為符號來使用,這個最高位就當作符號位。 符號位是 0 時表示正數,是 1 時表示負數。那么 -1 用二進制數該如何表示呢?可能很多人會這么認為:因為 1 的二進制數是 0000 0001,最高位是符號位,所以正確的表示 -1 應該是 1000 0001,但是這個答案真的對嗎?
計算機世界中是沒有減法的,計算機在做減法的時候其實就是在做加法,也就是用加法來實現的減法運算。比如 100 - 50 ,其實計算機來看的時候應該是 100 + (-50),為此,在表示負數的時候就要用到二進制補數,補數就是用正數來表示的負數。
為了獲得補數,需要將二進制的各數位的數值全部取反,然后再將結果 + 1 即可,先記住這個結論,下面來演示一下。

具體來說,就是需要先獲取某個數值的二進制數,然后對二進制數的每一位做取反操作(0 ---> 1 , 1 ---> 0),最后再對取反后的數 +1 ,這樣就完成了補數的獲取。
補數的獲取,雖然直觀上不易理解,但是邏輯上卻非常嚴謹,比如 1 - 1 的這個過程,首先用上面的這個 1000 0001(它是1的補數,不知道的請看上文,正確性先不管,只是用來做一下計算)來表示一下

奇怪,1 - 1 會變成 130 ,而不是0,所以可以得出結論 1000 0001 表示 -1 是完全錯誤的。
那么正確的該如何表示呢?其實是 1111 1111,來論證一下它的正確性

可以看到 1 - 1 其實實際上就是 1 + (-1),對 -1 進行上面的取反 + 1 后變為 1111 1111, 然后與 1 進行加法運算,得到的結果是九位的 1 0000 0000,結果發生了溢出,計算機會直接忽略掉溢出位,也就是直接拋掉 最高位 1 ,變為 0000 0000。也就是 0,結果正確,所以 1111 1111 表示的就是 -1 。
所以負數的二進制表示就是先求其補數,補數的求解過程就是對原始數值的二進制數各位取反,然后將結果 + 1。
算數右移和邏輯右移的區別
右移在移位后空出來的最高位有兩種情況 0 和1,將二進制數作為帶符號的數值進行右移運算時,移位后需要在最高位填充移位前符號位的值( 0 或 1)。這就被稱為算數右移。如果數值使用補數表示的負數值,那么右移后在空出來的最高位補 1,就可以正確的表示 1/2,1/4,1/8等的數值運算。如果是正數,那么直接在空出來的位置補 0 即可。
下面來看一個右移的例子。將 -4 右移兩位,看一下移位示意圖

如上圖所示,在邏輯右移的情況下, -4 右移兩位會變成 63, 顯然不是它的 1/4,所以不能使用邏輯右移,那么算數右移的情況下,右移兩位會變為 -1,顯然是它的 1/4,故而采用算數右移。 那么可以得出來一個結論:左移時,無論是圖形還是數值,移位后,只需要將低位補 0 即可;右移時,需要根據情況判斷是邏輯右移還是算數右移。 下面介紹一下符號擴展:將數據進行符號擴展是為了產生一個位數加倍、但數值大小不變的結果,以滿足有些指令對操作數位數的要求,例如倍長於除數的被除數,再如將數據位數加長以減少計算過程中的誤差。 以8位二進制為例,符號擴展就是指在保持值不變的前提下將其轉換成為16位和32位的二進制數。將0111 1111這個正的 8位二進制數轉換成為 16位二進制數時,很容易就能夠得出0000 0000 0111 1111這個正確的結果,但是像 1111 1111這樣的補數來表示的數值,該如何處理?直接將其表示成為1111 1111 1111 1111就可以了。也就是說,不管正數還是補數表示的負數,只需要將 0 和 1 填充高位即可。
磁盤
磁盤緩存
磁盤往往和內存是互利共生的關系,相互協作,彼此持有良好的合作關系。每次內存都需要從磁盤中讀取數據,必然會讀到相同的內容,所以一定會有一個角色負責存儲經常需要讀到的內容。做軟件的時候經常會用到緩存技術,那么硬件層面也不例外,磁盤也有緩存,磁盤的緩存叫做磁盤緩存。
磁盤緩存指的是把從磁盤中讀出的數據存儲到內存的方式,這樣一來,當接下來需要讀取相同的內容時,就不會再通過實際的磁盤,而是通過磁盤緩存來讀取。某一種技術或者框架的出現勢必要解決某種問題的,那么磁盤緩存就大大改善了磁盤訪問的速度。

虛擬內存
虛擬內存是內存和磁盤交互的第二個媒介。虛擬內存是指把磁盤的一部分作為假想內存來使用。這與磁盤緩存是假想的磁盤(實際上是內存)相對,虛擬內存是假想的內存(實際上是磁盤)。
虛擬內存是計算機系統內存管理的一種技術。它使得應用程序認為它擁有連續可用的內存(一個完整的地址空間),但是實際上,它通常被分割成多個物理碎片,還有部分存儲在外部磁盤管理器上,必要時進行數據交換。
通過借助虛擬內存,在內存不足時仍然可以運行程序。例如,在只剩 5MB 內存空間的情況下仍然可以運行 10MB 的程序。由於 CPU 只能執行加載到內存中的程序,因此,虛擬內存的空間就需要和內存中的空間進行置換(swap),然后運行程序。
虛擬內存與內存的交換方式
虛擬內存的方法有分頁式 和 分段式 兩種。Windows 采用的是分頁式。該方式是指在不考慮程序構造的情況下,把運行的程序按照一定大小的頁進行分割,並以頁為單位進行置換。在分頁式中,磁盤的內容讀到內存中稱為 Page In,內存的內容寫入磁盤稱為 Page Out。Windows 計算機的頁大小為 4KB ,也就是說,需要把應用程序按照 4KB 的頁來進行切分,以頁(page)為單位放到磁盤中,然后進行置換。

為了實現內存功能,Windows 在磁盤上提供了虛擬內存使用的文件(page file,頁文件)。該文件由 Windows 生成和管理,文件的大小和虛擬內存大小相同,通常大小是內存的 1 - 2 倍。
磁盤的物理結構
磁盤的物理結構指的是磁盤存儲數據的形式。
磁盤是通過其物理表面划分成多個空間來使用的。
划分的方式有兩種:
- 可變長方式:將物理結構划分成長度可變的空間
- 扇區方式。將磁盤結構划分為固定長度的空間。
一般 Windows 所使用的硬盤和軟盤都是使用扇區這種方式。扇區中,把磁盤表面分成若干個同心圓的空間就是 磁道,把磁道按照固定大小的存儲空間划分而成的就是 扇區

磁盤是通過其物理表面扇區是對磁盤進行物理讀寫的最小單位。Windows 中使用的磁盤,一般是一個扇區 512 個字節。不過,Windows 在邏輯方面對磁盤進行讀寫的單位是扇區整數倍簇。根據磁盤容量不同功能,1簇可以是 512 字節(1 簇 = 1扇區)、1KB(1簇 = 2扇區)、2KB、4KB、8KB、16KB、32KB( 1 簇 = 64 扇區)。簇和扇區的大小是相等的。划分成多個空間來使用的。划分的方式有兩種:可變長方式 和 扇區方式。前者是將物理結構划分成長度可變的空間,后者是將磁盤結構划分為固定長度的空間。一般 Windows 所使用的硬盤和軟盤都是使用扇區這種方式。扇區中,把磁盤表面分成若干個同心圓的空間就是 磁道,把磁道按照固定大小的存儲空間划分而成的就是 扇區
內存和磁盤的關系
程序不讀入內存就無法運行
計算機最主要的存儲部件是內存和磁盤。磁盤中存儲的程序必須加載到內存中才能運行,在磁盤中保存的程序是無法直接運行的,這是因為負責解析和運行程序內容的 CPU 是需要通過程序計數器來指定內存地址從而讀出程序指令的。

