CPU能夠直接訪問的通用存儲只有內存和處理器的內置的寄存器。機器指令能夠用內存地址做爲參數,而不能用磁盤地址做爲參數。因此執行指令以及指令使用的數據,應在這些可執行訪問的存儲設備上,若是數據不在內存中,那麼在CPU使用他們以前應把數據移到內存上。
CPU內置寄存器一般能夠在一個CPU時鐘週期內完成訪問,可是對於內存,完成內存的訪問可能須要多個CPU時鐘週期,這種結果形成的影響就是若是沒有數據用於完成正在執行的指令,那麼CPU可能將會屢次中斷(暫停)。因此須要在CPU和內存之間增長一個高速緩存。
爲了確保進程的執行正確,須要爲每一個進程分配一塊單獨的內存空間,從而使進程內存空間保護進程而互相不受到影響。經過兩個寄存器,一般爲基地址寄存器和界限地址寄存器。基地址寄存器中含有最小的合法的物理內存大小;界限地址寄存器中指定了進程範圍的大小。內存空間的保護實現是經過在CPU硬件對在用戶模式下產生的地址和寄存器的地址進行比較來完成的。也只有操做系統能夠經過特殊的特權指令,才能加載基地址寄存器和界限地址寄存器,由於特權指令只能在內核模式下執行,因此只有操做系統能夠加載基地址寄存器和界限地址寄存器。算法
一般程序是做爲二進制可執行文件存放在磁盤上的,若是須要執行的話,首先要將程序調入內存並放在進程中。在磁盤上等待調入內存以便執行的進程造成了輸入隊列。
大多數狀況下,用戶程序在執行前,須要通過好幾個步驟,在這些步驟中,地址可能會有不一樣的表示形式。源程序中地址一般使用符號表示,編譯器一般將這些符號地址綁定到可重定位的地址。連接程序或加載程序在將這些可重定位的地址綁定到絕對地址。每次綁定都是從一個地址空間到另外一個地址空間的映射。
一般,指令和數據綁定到存儲器地址可在沿途的任何一步中進行:緩存
CPU生成的地址一般稱爲邏輯地址,而內存單元看到的地址(即加載到內存地址寄存器的地址)一般是物理地址。編譯時和加載時的地址綁定方法生成相同的邏輯地址和物理地址,可是執行時的地址綁定方案生成不一樣的邏輯地址和物理地址。在這種狀況下,一般成邏輯地址爲虛擬地址。
從虛擬地址到物理地址的運行時映射是由**內存管理單元(MMU)**的硬件設備來完成。用戶進程所生成的地址在送交到內存以前,都將加上重定位寄存器的值(基地址寄存器)。而用戶程序不會看到真實的物理地址。spa
在以前的進程加載到內存中,是將進程的整個程序和全部數據都加載到物理內存當中,因此進程的大小受限於內存的大小,爲了得到內存空間利用率,能夠採用動態加載。採用動態加載時,一個程序只有在調用時纔會加載,全部程序都以可重定位加載格式保存在磁盤中。主程序被加載到內存並執行,當一個程序須要調用另外一個程序時,調用程序首先檢查另一個程序是否已經加載到內存中。若是沒有,可重定位連接程序會加載所需的程序到內存中,並更新程序的地址表以反映這個變化,接着控制傳遞給新加載的程序。因此,動態加載的好處就是,只有一個程序須要時纔會被加載。操作系統
動態連接庫是系統庫,可連接到用戶程序,以便運行。
若是是靜態連接的話,它的系統庫與其餘目標模塊同樣,經過加載程序被合併到二進制程序映像。可是動態連接庫相似動態加載(注意在這裏不是加載而是連接),會延遲到運行時。
若是有動態連接,在二進制映像中,每一個庫程序的引用都有一個存根。存根是一小段代碼,用來支出如何定位適當的內存駐留庫程序,或者在程序不在內存時應如何加載庫。當執行存根時,他首先檢查所需程序是否已經在內存中,若是不在,將程序加到內存中。存根會用程序地址來代替本身,並開始執行程序,因此下次在執行程序代碼的時候,就能夠直接進行,而不會因動態連接產生任何開銷。blog
進程必須在內存中以便執行,可是,進程能夠短暫的從內存交換到備份存儲,當再次執行時在調回到內存中。排序
標準交換在內存和備份存儲之間移動進程,備份存儲一般是快速磁盤。備份存儲應該足夠的大,以容納全部用戶的全部內存映像的副本,而且應提供對這些存儲器映像的直接訪問。系統維護一個可運行的全部進程的就緒隊列,他們的映像在備份存儲和內存中,當CPU調度器決定要執行一個進程時,它調用分派器。分派器檢查隊列中的下一個進程是否在內存中,若是不在且沒有空閒內存區域,那麼分派器會換出當前位於內存的一個進程並換入所需進程,而後從新加載寄存器,並將控制權給所選進程。隊列
移動系統一般不支持任何形式的交換,移動設備一般採用閃存,而不是空間更大的硬盤做爲他的永久存儲。蘋果的IOS和谷歌的Android的具體交換策略能夠自行百度。進程
連續內存分配是早期OS所採用的一種內存分配策略,在採用連續內存分配時每一個進程位於一個連續的內存區域,與包含下一個進程的內存相連。圖片
爲了放置進程訪問不屬於他們的內存,依舊經過重定位寄存器和界限寄存器來實現保護,MMU經過動態的將邏輯地址加上重定位寄存器的值。當CPU調度器選擇一個進程來執行時,做爲上下文切換工做的一部分,分派器會用正確的值來加載重定位寄存器和界限寄存器。因爲CPU所產生的每一個地址都須要與這些寄存器進行覈對,因此能夠保證操做系統和其餘用戶的程序和數據不受該運行進程的影響。內存
最簡單的內存分配方法,就是將內存分爲多個固定大小的分區。每一個分區能夠只包含一個進程。因此多道程序的程度受限於分區數。
對於可變分區方法,操做系統維護一張表,用於記錄哪些內存可用和哪些內存已用。開始時全部內存均可用於用戶進程,所以能夠做爲一大塊的可用內存,稱爲孔。最後內存有一個集合,以包含各類大小的孔。
一般可用的內存塊爲分散在內存裏的不一樣大小的孔的集合。當新進程須要內存時,系統爲該進程查找足夠大的孔。若是孔太大,那麼就分爲兩塊:一塊分給進程,一塊返回孔集合。這種方法是通用動態存儲分配問題的一個例子。從一組可用孔中選擇一個空閒孔的最經常使用方法有:
用於內存分配的首次適應和最優適應算法都會有外部碎片。對於內存的碎片能夠是內部碎片,也能夠是外部的。好比假設有一個18464字節大小的孔,有一個進程須要18462字節,若是隻能分配所要求的塊,那麼還剩下2字節的孔。所以一般按固定大小的塊爲單位來分配內存,採用這種方法,進程所分配的內存可能比所須要的大,這兩個數字之差稱爲內部碎片,這部份內存存在於分區內部,可是又不能用。
外部碎片的一種解決方法是緊縮,移動內存內容,以便將全部的空閒空間合併成一整塊。可是緊縮並非老是可能的。若是重定位是靜態的,而且在彙編時或加載時進行的,那麼就不能緊縮;只有重定位是動態的,且在運行時進行的,那麼才能夠採用緊縮。