來自網站https://blog.csdn.net/lvyibin890/article/details/82217193
操作系統有虛擬內存與物理內存的概念。在很久以前,還沒有虛擬內存概念的時候,程序尋址用的都是物理地址。程序能尋址的范圍是有限的,這取決於CPU的地址線條數。比如在32位平台下,尋址的范圍是2^32也就是4G。並且這是固定的,如果沒有虛擬內存,且每次開啟一個進程都給4G的物理內存,就可能會出現很多問題:
因為我的物理內存時有限的,當有多個進程要執行的時候,都要給4G內存,很顯然你內存小一點,這很快就分配完了,於是沒有得到分配資源的進程就只能等待。當一個進程執行完了以后,再將等待的進程裝入內存。這種頻繁的裝入內存的操作是很沒效率的。由於指令都是直接訪問物理內存的,那么我這個進程就可以修改其他進程的數據,甚至會修改內核地址空間的數據,這是我們不想看到的。因為內存時隨機分配的,所以程序運行的地址也是不正確的。
於是針對上面會出現的各種問題,虛擬內存就出來了。
在之前一篇文章中進程分配資源介紹過一個進程運行時都會得到4G的虛擬內存。這個虛擬內存你可以認為,每個進程都認為自己擁有4G的空間,這只是每個進程認為的,但是實際上,在虛擬內存對應的物理內存上,可能只對應的一點點的物理內存,實際用了多少內存,就會對應多少物理內存。
進程得到的這4G虛擬內存是一個連續的地址空間(這也只是進程認為),而實際上,它通常是被分隔成多個物理內存碎片,還有一部分存儲在外部磁盤存儲器上,在需要時進行數據交換。
進程開始要訪問一個地址,它可能會經歷下面的過程:
1、每次我要訪問地址空間上的某一個地址,都需要把地址翻譯為實際物理內存地址;
2、所有進程共享這整一塊物理內存,每個進程只把自己目前需要的虛擬地址空間映射到物理內存上;
3、進程需要知道哪些地址空間上的數據在物理內存上,哪些不在(可能這部分存儲在磁盤上),還有在物理內存上的哪里,這就需要通過頁表來記錄;
4、頁表的每一個表項分兩部分,第一部分記錄此頁是否在物理內存上,第二部分記錄物理內存頁的地址(如果在的話);
5、當進程訪問某個虛擬地址的時候,就會先去看頁表,如果發現對應的數據不在物理內存上,就會發生缺頁異常;
6、缺頁異常的處理過程,操作系統立即阻塞該進程,並將硬盤里對應的頁換入內存,然后使該進程就緒,如果內存已經滿了,沒有空地方了,那就找一個頁覆蓋,至於具體覆蓋的哪個頁,就需要看操作系統的頁面置換算法是怎么設計的了。