計(jì)算機(jī)存儲(chǔ)體系
先來看這張計(jì)算機(jī)存儲(chǔ)體系結(jié)構(gòu)圖。

計(jì)算機(jī)存儲(chǔ)體系.png
從上圖可以看到,越在上面的訪問速度越快,但是容量越小,今天要說的就是內(nèi)存那個(gè)環(huán)節(jié)。
內(nèi)存是什么
- 內(nèi)存是可以記錄二進(jìn)制數(shù)據(jù)一種器件,它是連續(xù)的結(jié)構(gòu),可以隨機(jī)讀寫,斷電會(huì)丟失數(shù)據(jù),所有程序必須從磁盤加載到內(nèi)存中才能運(yùn)行。
內(nèi)存空間管理策略
- 上面說了內(nèi)存是一個(gè)連續(xù)的線性結(jié)構(gòu),一個(gè)4G的內(nèi)存有很多個(gè)電容,把他們線性排在一起,那么就有034359738367個(gè)可以存bit的空位,計(jì)算機(jī)一般把8個(gè)bit合成一個(gè)byte存放,那么就有04294967295個(gè)byte,寫成16進(jìn)制就是 0x0 ~ 0xFFFFFFFF個(gè)地址,這個(gè)就是內(nèi)存地址了,每個(gè)地址里面可以取出一個(gè)字節(jié)的數(shù)據(jù)。
現(xiàn)在有0xFFFFFFFF個(gè)地址,人們是怎么利用操作系統(tǒng)去管理和分配這些地址給程序使用的呢?
- 為了方便說明問題,我把內(nèi)存地址用10進(jìn)制表示,轉(zhuǎn)成16進(jìn)制也是一樣的,16進(jìn)制不太方便人腦計(jì)算。我不用4G的內(nèi)存講,因?yàn)樘嗔耍?到99的內(nèi)存空間即可說明問題。我盡量用通俗的語言說明問題,沒有很復(fù)雜的概念,復(fù)雜的概念請翻看《操作系統(tǒng)原理》。
虛擬內(nèi)存地址與實(shí)際物理地址
-
在說怎么管理內(nèi)存之前,先要說一下虛擬內(nèi)存地址,最開始人們在程序直接使用實(shí)際的物理地址,如下圖:
假設(shè)程序a第一次啟動(dòng)被裝載在1的位置,第二次啟動(dòng)裝載在31的位置。
程序a中有段代碼 jmp 3,想去執(zhí)行3那里的目標(biāo)代碼。
物理地址.png
顯然第一次jmp是對的,但第二次操作系統(tǒng)把裝在了31的位置,顯然目標(biāo)代碼應(yīng)該是33了,就應(yīng)該把程序改為jmp 33,否則就出錯(cuò)了。
這就是直接使用物理地址的弊端,每次啟動(dòng)都要重新改代碼,或者把所有跳轉(zhuǎn)的地方都+30,很麻煩。所以現(xiàn)代程序都不直接使用物理地址,而是用了虛擬地址,如下圖
地址轉(zhuǎn)換.png
使用了虛擬地址后,每個(gè)程序就認(rèn)為自己是從0地址開始的就好了,不管加載到哪個(gè)地方,都不用在修改代碼,通過一個(gè)段表就可以把虛擬地址轉(zhuǎn)為實(shí)際的物理地址。 -
在編譯器debug中可以看到 0x0012fee8 這些都是虛擬地址,物理地址操作系統(tǒng)不允許直接訪問了。
vc6.0.png
段式管理
- 最開始人們用段式管理,但是段式管理會(huì)產(chǎn)生內(nèi)存碎片,過程如下圖
內(nèi)存碎片.png
當(dāng)程序c要加載進(jìn)內(nèi)存的時(shí)候,程序b前面的空間不夠了,只能從b后面分配,于是b前面的空間就不能給c利用,成為了內(nèi)存碎片。 - 操作系統(tǒng)為了避免這種情況,充分利用內(nèi)存空間,當(dāng)內(nèi)存不夠的時(shí)候,會(huì)采取內(nèi)存緊縮,就是把所有程序都往左邊挪動(dòng),全部緊緊的排在一起,但是實(shí)際中對4GB的內(nèi)存空間進(jìn)行緊縮的時(shí)候,需要5秒左右的時(shí)間,計(jì)算機(jī)經(jīng)??C(jī)5秒你能忍?
- 程序c分配內(nèi)存的策略有首先適配法,最佳適配法等方法,考慮到篇幅就不展開講了,我上面用的就是首先適配法,從左到右首次找到一個(gè)合適位置就分配。
頁式管理
- 由于段式管理的缺點(diǎn)(外部碎片,內(nèi)存緊縮),人們后來發(fā)明了頁式管理,通俗來說,頁式管理就是把一定大小的物理空間當(dāng)做一個(gè)頁框,整個(gè)內(nèi)存中就有很多個(gè)這樣的頁框,比如0到99的內(nèi)存空間,按10個(gè)字節(jié)為一個(gè)頁框,那么整個(gè)內(nèi)存就分成了10頁框,0到9是第0個(gè)頁框,如下圖:
頁框.png
按照頁式管理劃分空間后,一個(gè)程序用一個(gè)頁框要么使用頁框全部空間,要么不能使用,不能說只用一點(diǎn)點(diǎn),如果一個(gè)程序用不上那么多空間,也必須拿完,于是段式管理的外部碎片和內(nèi)存緊縮的問題被解決了,提高了內(nèi)存利用率,但是又產(chǎn)生內(nèi)存內(nèi)部碎片。 - 程序的頁和頁框的大小是一樣的,頁框大小如何確定?如果頁框太大,產(chǎn)生的內(nèi)部碎片也大,如果頁框太小,導(dǎo)致頁表變大,查找速度降低。例如4GB的內(nèi)存,按照4KB分為一頁,4GB / 4KB = 1048576項(xiàng),查找起來自然慢了。
虛擬地址到物理地址轉(zhuǎn)換過程

地址轉(zhuǎn)換.png
上圖還有個(gè)在不在位,這個(gè)位表示如果程序的頁在頁框中,那么直接轉(zhuǎn)換,如果不在頁框中,那么引發(fā)一個(gè)缺頁中斷,操作系統(tǒng)去磁盤上把缺失的頁加載進(jìn)內(nèi)存,然后程序才繼續(xù)往下運(yùn)行。這里有個(gè)重點(diǎn),運(yùn)行中的程序不一定全部在內(nèi)存中,也有可能在磁盤上,在磁盤上的那部分叫做虛擬內(nèi)存!,那究竟程序的哪些頁面在內(nèi)存中,哪些頁面在磁盤上,這里就涉及到頁面置換算法
頁面置換算法
一個(gè)程序的部分頁面在內(nèi)存中,部分頁面在磁盤上,究竟怎么確定這些頁面?
我選幾個(gè)來說
- 先進(jìn)先出(FIFO)
最簡單的,最先進(jìn)來的,就最先淘汰出去。缺點(diǎn):有些頻繁訪問的頁面也可能淘汰出去。 - 二次機(jī)會(huì)(SC)
最先進(jìn)來的頁面不一定最先出去,如果這個(gè)頁面的訪問標(biāo)志是1,那么把它置為0,再給它一次機(jī)會(huì),如果頁面訪問標(biāo)志0,那么才置換出去。 - 最近未使用(NRU)
每個(gè)頁面有兩個(gè)標(biāo)志位,標(biāo)記是否訪問,是否修改,顯然那么沒有怎么訪問,沒有修改的頁面會(huì)被淘汰出去。 - 最近最少使用(LRU)
這個(gè)也很好理解,每個(gè)頁面有個(gè)計(jì)數(shù)器,訪問一次就加1,顯然把訪問次數(shù)很少的那些優(yōu)先淘汰。 - 此外還有老化算法,工作集算法,等等,限于篇幅(其實(shí)是我寫累了)就不詳細(xì)敘說了,我已經(jīng)寫了個(gè)實(shí)驗(yàn)代碼,在這里可以看到。
段頁式管理
最后是段頁式管理,結(jié)合了段式頁式的優(yōu)缺點(diǎn),把程序先分段,在每個(gè)段內(nèi)再分頁,來管理內(nèi)存,windows操作系統(tǒng)就是用這個(gè)方法管理的,當(dāng)然實(shí)際中更加復(fù)雜,絕對沒有我說的這么簡單,我只是通俗的說清原理,詳情請看《操作系統(tǒng)原理》




