早期計算機都是直接訪問物理內存的,這樣想在內存中同時運行兩個程序是不可能的,想想為什么?
下面給出三種存儲模型:
第一種和第三種均不常用了,因為用戶程序一旦出現錯誤,可能會銷毀OS,當按上述方式裝載程序時,新裝載的程序會覆蓋掉先前裝載的程序。唯一能并行的方法就是使用多線程,但是會共享信息,所以不可行。
后來提出內存鍵的概念來區分在內存中多道程序,此時內存中可以裝載多道程序,但是一個程序可能因為jmp指令跳轉到另一個程序從而發生程序崩潰。這都是因為使用了絕對地址產生的問題,一種解決辦法是采用靜態重定位的方法,比如一個程序裝入到16000地址位,則程序中地址數都要加上16000這個常數,雖然這種方法一般來講是可行的,但是無法辨別它是重定位的地址還是不是重定位的地址,來了一個訪問地址,那這個訪問地址加不加16000,而且該方法會減慢裝載速度。
一種存儲器的抽象:地址空間
要想多個程序同時處于內存中就需要解決兩個問題:保護和重定向。我們希望每個程序都有自己獨立的一套地址空間。
一個簡單的方法是使用動態重定位,利用基址寄存器(存放程序開始地址)和界限寄存器(存放程序大?。?,當指令讀或寫數據字前,CPU硬件會將其發送到內存總線前與基址寄存器中的值相加,并判斷相加后的指令是否越界。但是每次都要做加法運算和比較運算就會顯得很慢。
交換技術的出現
將所有進程都裝載入內存是不大可能的,一種策略是將空閑進程存入磁盤,將需要使用的進程整個裝入內存;另一種策略是虛擬內存
交換在內存中產生了多個空閑區,通過把所有內存盡可能向下移動,有可能將這些小的內存區合并為大的內存區,這稱為內存壓縮,但通常不進行該操作,因為非常耗時,而且OS需要準確的按其需要的大小分配內存。
但是如果數據段可以增長,例如,很多程序語言都允許從堆中動態分配內存。所以我們可以為其預留一部分空間。
其中,堆棧存放私有變量和返回地址,向下增長。數據段作為堆使用供變量動態分配和釋放,向上增長。
空閑內存區管理-位圖方法
內存可能被劃分為小到幾個字,大到幾千字節的分配單元,每個分配單元對應位圖中的一位,0表示空閑,1表示占用。在分配一個k個分配單元的進程時,需要在位圖中查找k個連續的分配單元進行分配,這是非常耗時的。
空閑內存區管理-鏈表
還有一個方法是維護一個記錄已分配的內存段和空閑內存段的鏈表,設當X進程結束后同時需要合并內存。
當然,這里有很多算法可以分配內存,有首次適配法,下次適配法,最佳適配法(會生成更多的小的空閑區,可以考慮最差適配法)等。
虛擬內存
為了防止某程序過大,最開始采用覆蓋塊的方法,即手動切割程序成一個個小塊,但是怎么切割是個問題。于是這個問題干脆交給計算機去做,虛擬內存就誕生了。其基本思想是:
每個程序都有自己的基本空間,這個空間被分成多個塊,每個塊稱作一頁和頁面。(注意:虛擬內存就是利用磁盤空間來擴大內存,所以稱為虛擬)
放張圖就明白了:
這里,我們通過頁表(基址+偏移量)來管理頁面,也可以加上TLB(塊表),計算機組成原理的內容吧。有時,單個頁表是不夠表示頁面的,所以我們可以采用二級頁表或多級頁表,來看下面一張圖:
有頁面自然也有頁面置換算法,這些算法有最優頁面置換算法,最近未使用置換算法,先進先出置換算法等
在考慮如何交換時,如果考慮換出單個進程中最小生存時間的頁面稱為局部頁面置換算法,考慮換出整個內存中最小生存時間的頁面稱為全局頁面置換算法。通常情況下全局算法較好。另一種途徑是為進程平均分配頁面,剩余放入公共池里面。
我們也可以采用測試缺頁中斷率的方法。
同時,我們也應該選則合適的頁面大小,在共享方面,一般只讀的頁面可以作為共享頁面來減少內存消耗。
共享庫
在靜態鏈接.o程序時,會造成很大的內存消耗,因為要鏈接不同庫文件,這些庫文件直接裝載至內存。但是共享庫(又稱動態鏈接庫,DLL),只會裝載一小段能夠在運行時綁定被調用函數的存根例程,即用什么函數,才裝入對應的頁面而不是整個文件裝入。當然,如果其它程序裝載了該共享庫,則本程序就不需要裝載它了。
另外,如果DLL文件更新了,其并不需要重新編譯執行,用戶只需要下載更新的DLL文件下次啟動時即可使用。
來看兩個進程使用共享庫,需要用相對地址:
共享庫實際上是內存映射文件的一個特例。
如何進行缺頁中斷處理?
審核編輯:劉清
-
寄存器
+關注
關注
31文章
5363瀏覽量
120925 -
存儲器
+關注
關注
38文章
7527瀏覽量
164168 -
中斷處理
+關注
關注
0文章
94瀏覽量
10998
發布評論請先 登錄
相關推薦
評論