虛擬內存簡述

在遠古時期,內存極小,程序也不大,程序直接裝載到內存運行。但是隨着程序越來越複雜,理所應當的出現了這個問題,

如果程序所需內存比可用內存大,程序該如何運行?

爲了解決這個問題,當時提出了一種覆蓋裝入的技術,就是需要程序員自己把程序分割成若干個不相干的程序塊,塊與塊之間分別裝載運行。舉個很簡單的例子,程序裏面有兩個主要函數A和B,這兩個函數之間沒有相互調用關係,當需要A函數運行的時候,就把A函數對應的程序塊裝載到內存裏,等到執行完畢,再裝載別的塊。

這樣的操作不需要把程序全部裝入,暫時解決了上面提到的問題。爲什麼說是暫時解決呢?注意看上面那一段的黑體字部分,這種方法需要程序員自己去理清程序之間的關係,分割程序。程序邏輯相對簡單還比較ok,但是當程序更加的複雜,甚至程序代碼邏輯調用,根本分不出獨立的程序塊時,該如何解決?

其實上面那種方法就是現代虛擬內存技術的雛形。

 

要理解虛擬內存,我們先來慢慢理清幾個概念,

接下來,我們將理清這3個概念以及它們之間的關係:虛擬地址空間,物理內存空間,虛擬內存。

 

試問,當你在程序中輸出一個變量的地址時,這個地址的含義是什麼?

試問,你輸出一個全局變量的地址,幹掉程序,再啓動程序,爲什麼這個地址沒有改變?

試問,大家都知道,堆是向上增長,棧是向下增長,那棧和堆之間肯定有一大塊地址,這塊地址是不是浪費了?

嗯,好好思考一下~

 

不懂虛擬內存,就相當於沒學過操作系統。

 

每個進程都會有一個獨立的虛擬地址空間,注意,是獨立的,相互不能訪問的,地址空間裏包含了程序運行所需要的全部東西。進程運行時,所需要的所有數據,所有代碼,包括內核系統調用,運行庫之類的東西,全部取自虛擬地址空間。看到這你可能有疑問了,系統內核只有一個,確定是每個進程獨立擁有內核嗎?是的,在虛擬空間,每個進程都是獨立擁有的,進程所需要的所有東西,都會在虛擬地址空間有獨立的地址。

虛擬地址空間是操作系統爲每一個程序虛擬化出來的內存空間,虛擬地址空間的大小一般等於內存地址大小,程序裝載執行的時候操作系統生成,程序終止的時候消失。程序執行的時候,所有的操作,都是在虛擬地址空間上完成的,物理地址空間對於程序是不可知的狀態。程序跟物理地址是完全隔離的。你在程序中輸出的變量地址,就是這個變量在虛擬地址空間中的地址。

使用虛擬地址空間的好處:

1.虛擬地址空間是連續的,方便程序執行。

2.各個程序都有自己的一份虛擬地址空間,能隔離各個進程,一個進程中,函數溢出,可能會影響本進程的函數堆棧,但是絕對不會影響到別的進程。

3.節省內存空間。

 

前面還有很多沒有交代清楚,比如:

每個進程都有內存那麼大的地址空間,內存哪夠裝啊?

虛擬地址空間中有大塊的地方是沒有用到的,明明就浪費了空間,爲什麼說節省內存空間?

 

現在講一下,虛擬地址空間和物理內存的映射。

在編程中,基本的內存單位應該是字節了,也就是8bit。但是在內存管理中,這個顯然太小了,現代操作系統使用頁作爲內存管理的基本單位,一頁大小一般爲4K。現在想象一下,整個虛擬地址空間被劃分成很多個頁,整個物理內存也被劃分成很多個頁。大家都知道,程序是一條語句一條語句執行的,同一小時間段內,可能程序只會用到幾個頁的數據,別的頁處於閒置狀態。事實上,別扯什麼虛擬地址空間什麼的,代碼,數據只有在內存中才能被用到。操作系統做了虛擬地址空間和物理內存的映射,會把即將要用到的虛擬空間頁放入內存,不怎麼用到的頁移除,這個過程進程是感知不到的。進程只跟虛擬地址空間打交道,它用的時候,操作系統準備好了,所以在這個過程對它是無感知的。

地址映射的過程大概就是這樣:

程序正在執行,程序的虛擬地址空間一共有10個頁,程序執行的時候,操作系統把其中123頁映射到物理內存,程序用到了使用虛擬地址空間頁面1的時候,使用的是虛擬地址空間的地址,操作系統就把地址映射對應的物理內存頁上。再次強調,這個過程中,程序用到的地址都是虛擬地址,只不過操作系統給轉換成了物理地址。

等程序把頁面1用完了,現在想用頁面5,操作系統就會把地址映射到物理內存頁對應的5上,但是這個時候,發現內存中沒有頁面5,這是時候就會觸發缺頁中斷,把一個不怎麼用的頁淘汰掉(淘汰算法不再贅述),把頁面5加載到物理內存中。淘汰掉淘汰到哪了?數據不就丟了?沒丟,只是做了個映像,放到了虛擬內存中(也就是磁盤),加載是從哪加載的?從虛擬內存中加載。

 

這個虛擬內存是個啥?

不多說,大概可以理解爲,內存頁的備份。

從上面的過程可以看出來,虛擬地址空間中的空間,只有用到,纔會真實存在(加載到物理內存,或者扔到虛擬內存),如果沒用到的話,就什麼都沒有。就好像一個程序,只用到了10個頁,內存中加載了3個,虛擬內存中放了7個,虛擬地址空間很大,但是隻有用了纔會切切事實存在,比如現在申請了個地址,是第11個頁上的,那麼這個內存中就扔了一個頁出去,把這個頁擼進去,這時候,內存中3頁,虛擬內存中8頁。

 

emmmm,爲了描述的方便,我頁面是按連續的,要注意實際上的情況,比如虛擬地址空間4個G,也就是2^20 個頁,只要訪問到哪個頁面,哪個頁面就會被操作系統弄到內存裏,對於程序來說,它就是擁有了所有空間。

 

好了,還有好多東西沒有寫,比如裝載的時候動態庫靜態庫,虛擬地址空間中內存分佈模型,操作系統如何實現頁面置換的,頁表段表,多級映射,elf文件模型,等等

以後可能會慢慢補充,這次大概就寫到這裏,有什麼問題歡迎找我交流

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